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 */
35 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
36 #define parentDecl(st) ((st)->parent == NULL ? \
37 DECL_NONE : (st)->parent->declaration)
38 #define isType(token,t) (boolean) ((token)->type == (t))
39 #define insideEnumBody(st) (boolean) ((st)->parent == NULL ? FALSE : \
40 ((st)->parent->declaration == DECL_ENUM))
41 #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
42 ! (st)->haveQualifyingName && \
43 (st)->scope == SCOPE_EXTERN)
45 #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
51 enum { NumTokens
= 12 };
53 typedef enum eException
55 ExceptionNone
, ExceptionEOF
, ExceptionFormattingError
,
56 ExceptionBraceFormattingError
59 /* Used to specify type of keyword.
61 typedef enum eKeywordId
64 KEYWORD_ATTRIBUTE
, KEYWORD_ABSTRACT
, KEYWORD_ALIAS
,
65 KEYWORD_BOOLEAN
, KEYWORD_BYTE
, KEYWORD_BAD_STATE
, KEYWORD_BAD_TRANS
,
66 KEYWORD_BIND
, KEYWORD_BIND_VAR
, KEYWORD_BIT
, KEYWORD_BODY
,
67 KEYWORD_CASE
, KEYWORD_CATCH
, KEYWORD_CHAR
, KEYWORD_CLASS
, KEYWORD_CONST
,
68 KEYWORD_CONSTRAINT
, KEYWORD_COVERAGE_BLOCK
, KEYWORD_COVERAGE_DEF
,
69 KEYWORD_DEFAULT
, KEYWORD_DELEGATE
, KEYWORD_DELETE
, KEYWORD_DO
,
71 KEYWORD_ELSE
, KEYWORD_ENUM
, KEYWORD_EXPLICIT
, KEYWORD_EXTERN
,
72 KEYWORD_EXTENDS
, KEYWORD_EVENT
,
73 KEYWORD_FINAL
, KEYWORD_FINALLY
, KEYWORD_FLOAT
, KEYWORD_FOR
, KEYWORD_FRIEND
, KEYWORD_FUNCTION
,
74 KEYWORD_GET
, KEYWORD_GOTO
,
75 KEYWORD_IF
, KEYWORD_IMPLEMENTS
, KEYWORD_IMPORT
, KEYWORD_IN
, KEYWORD_INLINE
, KEYWORD_INT
,
76 KEYWORD_INOUT
, KEYWORD_INPUT
, KEYWORD_INTEGER
, KEYWORD_INTERFACE
,
78 KEYWORD_LOCAL
, KEYWORD_LONG
,
79 KEYWORD_M_BAD_STATE
, KEYWORD_M_BAD_TRANS
, KEYWORD_M_STATE
, KEYWORD_M_TRANS
,
80 KEYWORD_MODULE
, KEYWORD_MUTABLE
,
81 KEYWORD_NAMESPACE
, KEYWORD_NEW
, KEYWORD_NEWCOV
, KEYWORD_NATIVE
, KEYWORD_NOEXCEPT
,
82 KEYWORD_OPERATOR
, KEYWORD_OUT
, KEYWORD_OUTPUT
, KEYWORD_OVERLOAD
, KEYWORD_OVERRIDE
,
83 KEYWORD_PACKED
, KEYWORD_PORT
, KEYWORD_PACKAGE
, KEYWORD_PRIVATE
,
84 KEYWORD_PROGRAM
, KEYWORD_PROTECTED
, KEYWORD_PUBLIC
,
85 KEYWORD_REF
, KEYWORD_REGISTER
, KEYWORD_RETURN
,
86 KEYWORD_SHADOW
, KEYWORD_STATE
,
87 KEYWORD_SET
, KEYWORD_SHORT
, KEYWORD_SIGNAL
, KEYWORD_SIGNED
, KEYWORD_SIZE_T
, KEYWORD_STATIC
,
88 KEYWORD_STATIC_ASSERT
, KEYWORD_STRING
,
89 KEYWORD_STRUCT
, KEYWORD_SWITCH
, KEYWORD_SYNCHRONIZED
,
90 KEYWORD_TASK
, KEYWORD_TEMPLATE
, KEYWORD_THIS
, KEYWORD_THROW
,
91 KEYWORD_THROWS
, KEYWORD_TRANSIENT
, KEYWORD_TRANS
, KEYWORD_TRANSITION
,
92 KEYWORD_TRY
, KEYWORD_TYPEDEF
, KEYWORD_TYPENAME
,
93 KEYWORD_UINT
, KEYWORD_ULONG
, KEYWORD_UNION
, KEYWORD_UNSIGNED
, KEYWORD_USHORT
,
95 KEYWORD_VIRTUAL
, KEYWORD_VOID
, KEYWORD_VOLATILE
,
96 KEYWORD_WCHAR_T
, KEYWORD_WEAK
, KEYWORD_WHILE
99 /* Used to determine whether keyword is valid for the current language and
102 typedef struct sKeywordDesc
106 short isValid
[7]; /* indicates languages for which kw is valid */
109 /* Used for reporting the type of object parsed by nextToken ().
111 typedef enum eTokenType
113 TOKEN_NONE
, /* none */
114 TOKEN_ARGS
, /* a parenthetical pair and its contents */
117 TOKEN_COMMA
, /* the comma character */
118 TOKEN_DOUBLE_COLON
, /* double colon indicates nested-name-specifier */
120 TOKEN_NAME
, /* an unknown name */
121 TOKEN_PACKAGE
, /* a Java package name */
122 TOKEN_PAREN_NAME
, /* a single name in parentheses */
123 TOKEN_SEMICOLON
, /* the semicolon character */
124 TOKEN_SPEC
, /* a storage class specifier, qualifier, type, etc. */
125 TOKEN_STAR
, /* pointer detection */
126 TOKEN_ARRAY
, /* array detection */
130 /* This describes the scoping of the current statement.
132 typedef enum eTagScope
134 SCOPE_GLOBAL
, /* no storage class specified */
135 SCOPE_STATIC
, /* static storage class */
136 SCOPE_EXTERN
, /* external storage class */
137 SCOPE_FRIEND
, /* declares access only */
138 SCOPE_TYPEDEF
, /* scoping depends upon context */
142 typedef enum eDeclaration
145 DECL_BASE
, /* base type (default) */
151 DECL_FUNCTION_TEMPLATE
,
152 DECL_IGNORE
, /* non-taggable "declaration" */
156 DECL_NOMANGLE
, /* C++ name demangling block */
163 typedef enum eVisibilityType
169 ACCESS_DEFAULT
, /* Java-specific */
173 /* Information about the parent class of a member (if any).
175 typedef struct sMemberInfo
177 accessType access
; /* access of current statement */
178 accessType accessDefault
; /* access default for current statement */
181 typedef struct sTokenInfo
185 vString
* name
; /* the name of the token */
186 unsigned long lineNumber
; /* line number of tag */
187 MIOPos filePosition
; /* file position of line containing name */
190 typedef enum eImplementation
199 /* Describes the statement currently undergoing analysis.
201 typedef struct sStatementInfo
204 declType declaration
; /* specifier associated with TOKEN_SPEC */
205 boolean gotName
; /* was a name parsed yet? */
206 boolean haveQualifyingName
; /* do we have a name we are considering? */
207 boolean gotParenName
; /* was a name inside parentheses parsed yet? */
208 boolean gotArgs
; /* was a list of parameters parsed yet? */
209 unsigned int nSemicolons
; /* how many semicolons did we see in that statement */
210 impType implementation
; /* abstract or concrete implementation? */
211 unsigned int tokenIndex
; /* currently active token */
212 tokenInfo
* token
[((int) NumTokens
)];
213 tokenInfo
* context
; /* accumulated scope of current statement */
214 tokenInfo
* blockName
; /* name of current block */
215 memberInfo member
; /* information regarding parent class/struct */
216 vString
* parentClasses
; /* parent classes */
217 struct sStatementInfo
*parent
; /* statement we are nested within */
218 long argEndPosition
; /* Position where argument list ended */
219 tokenInfo
* firstToken
; /* First token in the statement */
222 /* Describes the type of tag being generated.
224 typedef enum eTagType
227 TAG_CLASS
, /* class name */
228 TAG_ENUM
, /* enumeration name */
229 TAG_ENUMERATOR
, /* enumerator (enumeration value) */
230 TAG_FIELD
, /* field (Java) */
231 TAG_FUNCTION
, /* function definition */
232 TAG_INTERFACE
, /* interface declaration */
233 TAG_MEMBER
, /* structure, class or interface member */
234 TAG_METHOD
, /* method declaration */
235 TAG_NAMESPACE
, /* namespace name */
236 TAG_PACKAGE
, /* package name */
237 TAG_PROTOTYPE
, /* function prototype or declaration */
238 TAG_STRUCT
, /* structure name */
239 TAG_TYPEDEF
, /* typedef name */
240 TAG_UNION
, /* union name */
241 TAG_VARIABLE
, /* variable definition */
242 TAG_EXTERN_VAR
, /* external variable declaration */
243 TAG_MACRO
, /* #define s */
244 TAG_EVENT
, /* event */
245 TAG_SIGNAL
, /* signal */
246 TAG_LOCAL
, /* local variable definition */
247 TAG_PROPERTY
, /* property name */
248 TAG_COUNT
/* must be last */
251 typedef struct sParenInfo
254 boolean isKnrParamList
;
255 boolean isNameCandidate
;
256 boolean invalidContents
;
258 unsigned int parameterCount
;
265 static jmp_buf Exception
;
267 static langType Lang_c
;
268 static langType Lang_cpp
;
269 static langType Lang_csharp
;
270 static langType Lang_java
;
271 static langType Lang_d
;
272 static langType Lang_glsl
;
273 static langType Lang_ferite
;
274 static langType Lang_vala
;
276 /* Used to index into the CKinds table. */
280 CK_CLASS
, CK_DEFINE
, CK_ENUMERATOR
, CK_FUNCTION
,
281 CK_ENUMERATION
, CK_MEMBER
, CK_NAMESPACE
, CK_PROTOTYPE
,
282 CK_STRUCT
, CK_TYPEDEF
, CK_UNION
, CK_VARIABLE
,
286 static kindOption CKinds
[] = {
287 { TRUE
, 'c', "class", "classes"},
288 { TRUE
, 'd', "macro", "macro definitions"},
289 { TRUE
, 'e', "enumerator", "enumerators (values inside an enumeration)"},
290 { TRUE
, 'f', "function", "function definitions"},
291 { TRUE
, 'g', "enum", "enumeration names"},
292 { TRUE
, 'm', "member", "class, struct, and union members"},
293 { TRUE
, 'n', "namespace", "namespaces"},
294 { FALSE
, 'p', "prototype", "function prototypes"},
295 { TRUE
, 's', "struct", "structure names"},
296 { TRUE
, 't', "typedef", "typedefs"},
297 { TRUE
, 'u', "union", "union names"},
298 { TRUE
, 'v', "variable", "variable definitions"},
299 { FALSE
, 'x', "externvar", "external variable declarations"},
302 /* Used to index into the DKinds table. */
306 DK_CLASS
, DK_ENUMERATOR
, DK_FUNCTION
,
307 DK_ENUMERATION
, DK_INTERFACE
, DK_MEMBER
, DK_NAMESPACE
, DK_PROTOTYPE
,
308 DK_STRUCT
, DK_TYPEDEF
, DK_UNION
, DK_VARIABLE
,
312 static kindOption DKinds
[] = {
313 { TRUE
, 'c', "class", "classes"},
314 { TRUE
, 'e', "enumerator", "enumerators (values inside an enumeration)"},
315 { TRUE
, 'f', "function", "function definitions"},
316 { TRUE
, 'g', "enum", "enumeration names"},
317 { TRUE
, 'i', "interface", "interfaces"},
318 { TRUE
, 'm', "member", "class, struct, and union members"},
319 { TRUE
, 'n', "namespace", "namespaces"},
320 { FALSE
, 'p', "prototype", "function prototypes"},
321 { TRUE
, 's', "struct", "structure names"},
322 { TRUE
, 't', "typedef", "typedefs"},
323 { TRUE
, 'u', "union", "union names"},
324 { TRUE
, 'v', "variable", "variable definitions"},
325 { FALSE
, 'x', "externvar", "external variable declarations"},
328 /* Used to index into the JavaKinds table. */
332 JK_CLASS
, JK_FIELD
, JK_INTERFACE
, JK_METHOD
,
333 JK_PACKAGE
, JK_ENUMERATOR
, JK_ENUMERATION
336 static kindOption JavaKinds
[] = {
337 { TRUE
, 'c', "class", "classes"},
338 { TRUE
, 'f', "field", "fields"},
339 { TRUE
, 'i', "interface", "interfaces"},
340 { TRUE
, 'm', "method", "methods"},
341 { TRUE
, 'p', "package", "packages"},
342 { TRUE
, 'e', "enumConstant", "enum constants"},
343 { TRUE
, 'g', "enum", "enum types"},
349 CSK_CLASS
, CSK_DEFINE
, CSK_ENUMERATOR
, CSK_EVENT
, CSK_FIELD
,
350 CSK_ENUMERATION
, CSK_INTERFACE
, CSK_LOCAL
, CSK_METHOD
,
351 CSK_NAMESPACE
, CSK_PROPERTY
, CSK_STRUCT
, CSK_TYPEDEF
354 static kindOption CsharpKinds
[] = {
355 { TRUE
, 'c', "class", "classes"},
356 { TRUE
, 'd', "macro", "macro definitions"},
357 { TRUE
, 'e', "enumerator", "enumerators (values inside an enumeration)"},
358 { TRUE
, 'E', "event", "events"},
359 { TRUE
, 'f', "field", "fields"},
360 { TRUE
, 'g', "enum", "enumeration names"},
361 { TRUE
, 'i', "interface", "interfaces"},
362 { FALSE
, 'l', "local", "local variables"},
363 { TRUE
, 'm', "method", "methods"},
364 { TRUE
, 'n', "namespace", "namespaces"},
365 { TRUE
, 'p', "property", "properties"},
366 { TRUE
, 's', "struct", "structure names"},
367 { TRUE
, 't', "typedef", "typedefs"},
372 VK_CLASS
, VK_DEFINE
, VK_ENUMERATOR
, VK_FIELD
,
373 VK_ENUMERATION
, VK_INTERFACE
, VK_LOCAL
, VK_METHOD
,
374 VK_NAMESPACE
, VK_PROPERTY
, VK_SIGNAL
, VK_STRUCT
377 static kindOption ValaKinds
[] = {
378 { TRUE
, 'c', "class", "classes"},
379 { TRUE
, 'd', "macro", "macro definitions"},
380 { TRUE
, 'e', "enumerator", "enumerators (values inside an enumeration)"},
381 { TRUE
, 'f', "field", "fields"},
382 { TRUE
, 'g', "enum", "enumeration names"},
383 { TRUE
, 'i', "interface", "interfaces"},
384 { FALSE
, 'l', "local", "local variables"},
385 { TRUE
, 'm', "method", "methods"},
386 { TRUE
, 'n', "namespace", "namespaces"},
387 { TRUE
, 'p', "property", "properties"},
388 { TRUE
, 'S', "signal", "signals"},
389 { TRUE
, 's', "struct", "structure names"},
392 /* Note: some keyword aliases are added in initializeDParser, initializeValaParser */
393 static const keywordDesc KeywordTable
[] = {
395 /* ANSI C | C# Java */
399 /* keyword keyword ID | | | | | | | */
400 { "__attribute__", KEYWORD_ATTRIBUTE
, { 1, 1, 1, 0, 0, 0, 1 } },
401 { "abstract", KEYWORD_ABSTRACT
, { 0, 0, 1, 1, 0, 1, 1 } },
402 { "bad_state", KEYWORD_BAD_STATE
, { 0, 0, 0, 0, 1, 0, 0 } },
403 { "bad_trans", KEYWORD_BAD_TRANS
, { 0, 0, 0, 0, 1, 0, 0 } },
404 { "bind", KEYWORD_BIND
, { 0, 0, 0, 0, 1, 0, 0 } },
405 { "bind_var", KEYWORD_BIND_VAR
, { 0, 0, 0, 0, 1, 0, 0 } },
406 { "bit", KEYWORD_BIT
, { 0, 0, 0, 0, 1, 0, 0 } },
407 { "body", KEYWORD_BODY
, { 0, 0, 0, 0, 0, 0, 1 } },
408 { "boolean", KEYWORD_BOOLEAN
, { 0, 0, 0, 1, 0, 0, 0 } },
409 { "byte", KEYWORD_BYTE
, { 0, 0, 0, 1, 0, 0, 1 } },
410 { "case", KEYWORD_CASE
, { 1, 1, 1, 1, 0, 1, 1 } },
411 { "catch", KEYWORD_CATCH
, { 0, 1, 1, 0, 0, 1, 1 } },
412 { "char", KEYWORD_CHAR
, { 1, 1, 1, 1, 0, 1, 1 } },
413 { "class", KEYWORD_CLASS
, { 0, 1, 1, 1, 1, 1, 1 } },
414 { "const", KEYWORD_CONST
, { 1, 1, 1, 1, 0, 1, 1 } },
415 { "constraint", KEYWORD_CONSTRAINT
, { 0, 0, 0, 0, 1, 0, 0 } },
416 { "coverage_block", KEYWORD_COVERAGE_BLOCK
, { 0, 0, 0, 0, 1, 0, 0 } },
417 { "coverage_def", KEYWORD_COVERAGE_DEF
, { 0, 0, 0, 0, 1, 0, 0 } },
418 { "do", KEYWORD_DO
, { 1, 1, 1, 1, 0, 1, 1 } },
419 { "default", KEYWORD_DEFAULT
, { 1, 1, 1, 1, 0, 1, 1 } },
420 { "delegate", KEYWORD_DELEGATE
, { 0, 0, 1, 0, 0, 1, 1 } },
421 { "delete", KEYWORD_DELETE
, { 0, 1, 0, 0, 0, 1, 1 } },
422 { "double", KEYWORD_DOUBLE
, { 1, 1, 1, 1, 0, 1, 1 } },
423 { "else", KEYWORD_ELSE
, { 1, 1, 0, 1, 0, 1, 1 } },
424 { "enum", KEYWORD_ENUM
, { 1, 1, 1, 1, 1, 1, 1 } },
425 { "event", KEYWORD_EVENT
, { 0, 0, 1, 0, 1, 0, 0 } },
426 { "explicit", KEYWORD_EXPLICIT
, { 0, 1, 1, 0, 0, 0, 1 } },
427 { "extends", KEYWORD_EXTENDS
, { 0, 0, 0, 1, 1, 0, 0 } },
428 { "extern", KEYWORD_EXTERN
, { 1, 1, 1, 0, 1, 1, 0 } },
429 { "extern", KEYWORD_NAMESPACE
, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
430 { "final", KEYWORD_FINAL
, { 0, 0, 0, 1, 0, 0, 1 } },
431 { "finally", KEYWORD_FINALLY
, { 0, 0, 0, 0, 0, 1, 1 } },
432 { "float", KEYWORD_FLOAT
, { 1, 1, 1, 1, 0, 1, 1 } },
433 { "for", KEYWORD_FOR
, { 1, 1, 1, 1, 0, 1, 1 } },
434 { "friend", KEYWORD_FRIEND
, { 0, 1, 0, 0, 0, 0, 0 } },
435 { "function", KEYWORD_FUNCTION
, { 0, 0, 0, 0, 1, 0, 1 } },
436 { "get", KEYWORD_GET
, { 0, 0, 0, 0, 0, 1, 0 } },
437 { "goto", KEYWORD_GOTO
, { 1, 1, 1, 1, 0, 1, 1 } },
438 { "if", KEYWORD_IF
, { 1, 1, 1, 1, 0, 1, 1 } },
439 { "implements", KEYWORD_IMPLEMENTS
, { 0, 0, 0, 1, 0, 0, 0 } },
440 { "import", KEYWORD_IMPORT
, { 0, 0, 0, 1, 0, 0, 1 } },
441 { "inline", KEYWORD_INLINE
, { 0, 1, 0, 0, 0, 1, 0 } },
442 { "in", KEYWORD_IN
, { 0, 0, 0, 0, 0, 0, 1 } },
443 { "inout", KEYWORD_INOUT
, { 0, 0, 0, 0, 1, 0, 0 } },
444 { "inout", KEYWORD_CONST
, { 0, 0, 0, 0, 0, 0, 1 } }, /* treat like const */
445 { "input", KEYWORD_INPUT
, { 0, 0, 0, 0, 1, 0, 0 } },
446 { "int", KEYWORD_INT
, { 1, 1, 1, 1, 0, 1, 1 } },
447 { "integer", KEYWORD_INTEGER
, { 0, 0, 0, 0, 1, 0, 0 } },
448 { "interface", KEYWORD_INTERFACE
, { 0, 0, 1, 1, 1, 1, 1 } },
449 { "internal", KEYWORD_INTERNAL
, { 0, 0, 1, 0, 0, 0, 0 } },
450 { "local", KEYWORD_LOCAL
, { 0, 0, 0, 0, 1, 0, 0 } },
451 { "long", KEYWORD_LONG
, { 1, 1, 1, 1, 0, 1, 1 } },
452 { "m_bad_state", KEYWORD_M_BAD_STATE
, { 0, 0, 0, 0, 1, 0, 0 } },
453 { "m_bad_trans", KEYWORD_M_BAD_TRANS
, { 0, 0, 0, 0, 1, 0, 0 } },
454 { "m_state", KEYWORD_M_STATE
, { 0, 0, 0, 0, 1, 0, 0 } },
455 { "m_trans", KEYWORD_M_TRANS
, { 0, 0, 0, 0, 1, 0, 0 } },
456 { "mutable", KEYWORD_MUTABLE
, { 0, 1, 0, 0, 0, 0, 0 } },
457 { "module", KEYWORD_MODULE
, { 0, 0, 0, 0, 0, 0, 1 } },
458 { "namespace", KEYWORD_NAMESPACE
, { 0, 1, 1, 0, 0, 1, 0 } },
459 { "native", KEYWORD_NATIVE
, { 0, 0, 0, 1, 0, 0, 0 } },
460 { "new", KEYWORD_NEW
, { 0, 1, 1, 1, 0, 1, 1 } },
461 { "newcov", KEYWORD_NEWCOV
, { 0, 0, 0, 0, 1, 0, 0 } },
462 { "noexcept", KEYWORD_NOEXCEPT
, { 0, 1, 0, 0, 0, 0, 0 } },
463 { "operator", KEYWORD_OPERATOR
, { 0, 1, 1, 0, 0, 0, 0 } },
464 { "out", KEYWORD_OUT
, { 0, 0, 0, 0, 0, 1, 1 } },
465 { "output", KEYWORD_OUTPUT
, { 0, 0, 0, 0, 1, 0, 0 } },
466 { "overload", KEYWORD_OVERLOAD
, { 0, 1, 0, 0, 0, 0, 0 } },
467 { "override", KEYWORD_OVERRIDE
, { 0, 0, 1, 0, 0, 1, 1 } },
468 { "package", KEYWORD_PACKAGE
, { 0, 0, 0, 1, 0, 0, 1 } },
469 { "packed", KEYWORD_PACKED
, { 0, 0, 0, 0, 1, 0, 0 } },
470 { "port", KEYWORD_PORT
, { 0, 0, 0, 0, 1, 0, 0 } },
471 { "private", KEYWORD_PRIVATE
, { 0, 1, 1, 1, 0, 1, 1 } },
472 { "program", KEYWORD_PROGRAM
, { 0, 0, 0, 0, 1, 0, 0 } },
473 { "protected", KEYWORD_PROTECTED
, { 0, 1, 1, 1, 1, 1, 1 } },
474 { "public", KEYWORD_PUBLIC
, { 0, 1, 1, 1, 1, 1, 1 } },
475 { "ref", KEYWORD_REF
, { 0, 0, 0, 0, 0, 1, 1 } },
476 { "register", KEYWORD_REGISTER
, { 1, 1, 0, 0, 0, 0, 0 } },
477 { "return", KEYWORD_RETURN
, { 1, 1, 1, 1, 0, 1, 1 } },
478 { "set", KEYWORD_SET
, { 0, 0, 0, 0, 0, 1, 0 } },
479 { "shadow", KEYWORD_SHADOW
, { 0, 0, 0, 0, 1, 0, 0 } },
480 { "short", KEYWORD_SHORT
, { 1, 1, 1, 1, 0, 1, 1 } },
481 { "signal", KEYWORD_SIGNAL
, { 0, 0, 0, 0, 0, 1, 0 } },
482 { "signed", KEYWORD_SIGNED
, { 1, 1, 0, 0, 0, 0, 0 } },
483 { "size_t", KEYWORD_SIZE_T
, { 0, 0, 0, 0, 0, 1, 0 } },
484 { "state", KEYWORD_STATE
, { 0, 0, 0, 0, 1, 0, 0 } },
485 { "static", KEYWORD_STATIC
, { 1, 1, 1, 1, 1, 1, 1 } },
486 { "static_assert", KEYWORD_STATIC_ASSERT
, { 0, 1, 0, 0, 0, 0, 0 } },
487 { "string", KEYWORD_STRING
, { 0, 0, 1, 0, 1, 1, 0 } },
488 { "struct", KEYWORD_STRUCT
, { 1, 1, 1, 0, 0, 1, 1 } },
489 { "switch", KEYWORD_SWITCH
, { 1, 1, 1, 1, 0, 1, 1 } },
490 { "synchronized", KEYWORD_SYNCHRONIZED
, { 0, 0, 0, 1, 0, 0, 1 } },
491 { "task", KEYWORD_TASK
, { 0, 0, 0, 0, 1, 0, 0 } },
492 { "template", KEYWORD_TEMPLATE
, { 0, 1, 0, 0, 0, 0, 0 } },
493 { "template", KEYWORD_NAMESPACE
, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
494 { "this", KEYWORD_THIS
, { 0, 0, 1, 1, 0, 1, 0 } }, /* 0 to allow D ctor tags */
495 { "throw", KEYWORD_THROW
, { 0, 1, 1, 1, 0, 1, 1 } },
496 { "throws", KEYWORD_THROWS
, { 0, 0, 0, 1, 0, 1, 0 } },
497 { "trans", KEYWORD_TRANS
, { 0, 0, 0, 0, 1, 0, 0 } },
498 { "transition", KEYWORD_TRANSITION
, { 0, 0, 0, 0, 1, 0, 0 } },
499 { "transient", KEYWORD_TRANSIENT
, { 0, 0, 0, 1, 0, 0, 0 } },
500 { "try", KEYWORD_TRY
, { 0, 1, 1, 0, 0, 1, 1 } },
501 { "typedef", KEYWORD_TYPEDEF
, { 1, 1, 1, 0, 1, 0, 1 } },
502 { "typename", KEYWORD_TYPENAME
, { 0, 1, 0, 0, 0, 0, 0 } },
503 { "uint", KEYWORD_UINT
, { 0, 0, 1, 0, 0, 1, 1 } },
504 { "ulong", KEYWORD_ULONG
, { 0, 0, 1, 0, 0, 1, 1 } },
505 { "union", KEYWORD_UNION
, { 1, 1, 0, 0, 0, 0, 1 } },
506 { "unsigned", KEYWORD_UNSIGNED
, { 1, 1, 1, 0, 0, 0, 1 } },
507 { "ushort", KEYWORD_USHORT
, { 0, 0, 1, 0, 0, 1, 1 } },
508 { "using", KEYWORD_USING
, { 0, 1, 1, 0, 0, 1, 0 } },
509 { "virtual", KEYWORD_VIRTUAL
, { 0, 1, 1, 0, 1, 1, 0 } },
510 { "void", KEYWORD_VOID
, { 1, 1, 1, 1, 1, 1, 1 } },
511 { "volatile", KEYWORD_VOLATILE
, { 1, 1, 1, 1, 0, 0, 1 } },
512 { "wchar_t", KEYWORD_WCHAR_T
, { 0, 1, 1, 0, 0, 0, 0 } },
513 { "weak", KEYWORD_WEAK
, { 0, 0, 0, 0, 0, 1, 0 } },
514 { "while", KEYWORD_WHILE
, { 1, 1, 1, 1, 0, 1, 1 } }
519 * FUNCTION PROTOTYPES
521 static void createTags (const unsigned int nestLevel
, statementInfo
*const parent
);
522 static void copyToken (tokenInfo
*const dest
, const tokenInfo
*const src
);
523 static const char *getVarType (const statementInfo
*const st
,
524 const tokenInfo
*const token
);
527 * FUNCTION DEFINITIONS
530 /* Debugging functions added by Biswa */
531 #if defined(DEBUG_C) && DEBUG_C
532 static char *tokenTypeName
[] = {
533 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
534 "package", "paren-name", "';'", "spec", "*", "[]", "count"
537 static char *tagScopeNames
[] = {
538 "global", "static", "extern", "friend", "typedef", "count"};
540 static char *declTypeNames
[] = {
541 "none", "base", "class", "enum", "function", "ignore", "interface",
542 "namespace", "nomangle", "package", "struct", "union", "count"};
544 static char *impTypeNames
[] = {
545 "default", "abstract", "virtual", "pure-virtual", "count"};
547 void printToken(const tokenInfo
*const token
)
549 fprintf(stderr
, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName
[token
->type
],
550 token
->keyword
, vStringValue(token
->name
));
553 void printTagEntry(const tagEntryInfo
*tag
)
555 fprintf(stderr
, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag
->name
,
556 tag
->kindName
, tag
->extensionFields
.implementation
, tag
->extensionFields
.scope
[1],
557 tag
->extensionFields
.varType
);
560 void printStatement(const statementInfo
*const statement
)
563 statementInfo
*st
= (statementInfo
*) statement
;
566 fprintf(stderr
, "Statement Info:\n------------------------\n");
567 fprintf(stderr
, "scope: %s, decl: %s, impl: %s\n", tagScopeNames
[st
->scope
],
568 declTypeNames
[st
->declaration
], impTypeNames
[st
->implementation
]);
569 for (i
=0; i
< NumTokens
; ++i
)
571 fprintf(stderr
, "Token %d %s: ", i
, (i
== st
->tokenIndex
)?"(current)":"");
572 printToken(st
->token
[i
]);
574 fprintf(stderr
, "Context: ");
575 printToken(st
->context
);
576 fprintf(stderr
, "Block: ");
577 printToken(st
->blockName
);
578 fprintf(stderr
, "Parent classes: %s\n", vStringValue(st
->parentClasses
));
579 fprintf(stderr
, "First token: ");
580 printToken(st
->firstToken
);
581 if (NULL
!= st
->parent
)
582 fprintf(stderr
, "Printing Parent:\n");
585 fprintf(stderr
, "-----------------------------------------------\n");
589 extern boolean
includingDefineTags (void)
591 if (isLanguage(Lang_c
) ||
592 isLanguage(Lang_cpp
) ||
593 isLanguage(Lang_csharp
) ||
594 isLanguage(Lang_ferite
) ||
595 isLanguage(Lang_glsl
) ||
596 isLanguage(Lang_vala
))
597 return CKinds
[CK_DEFINE
].enabled
;
606 static void initToken (tokenInfo
* const token
)
608 token
->type
= TOKEN_NONE
;
609 token
->keyword
= KEYWORD_NONE
;
610 token
->lineNumber
= getSourceLineNumber();
611 token
->filePosition
= getInputFilePosition();
612 vStringClear(token
->name
);
615 static void advanceToken (statementInfo
* const st
)
617 if (st
->tokenIndex
>= (unsigned int) NumTokens
- 1)
621 initToken(st
->token
[st
->tokenIndex
]);
624 static tokenInfo
*prevToken (const statementInfo
*const st
, unsigned int n
)
626 unsigned int tokenIndex
;
627 unsigned int num
= (unsigned int) NumTokens
;
629 tokenIndex
= (st
->tokenIndex
+ num
- n
) % num
;
631 return st
->token
[tokenIndex
];
634 static void setToken (statementInfo
*const st
, const tokenType type
)
637 token
= activeToken (st
);
642 static void retardToken (statementInfo
*const st
)
644 if (st
->tokenIndex
== 0)
645 st
->tokenIndex
= (unsigned int) NumTokens
- 1;
648 setToken(st
, TOKEN_NONE
);
651 static tokenInfo
*newToken (void)
653 tokenInfo
*const token
= xMalloc (1, tokenInfo
);
654 token
->name
= vStringNew();
659 static void deleteToken (tokenInfo
*const token
)
663 vStringDelete(token
->name
);
668 static const char *accessString (const accessType laccess
)
670 static const char *const names
[] = {
671 "?", "private", "protected", "public", "default"
673 Assert (sizeof (names
) / sizeof (names
[0]) == ACCESS_COUNT
);
674 Assert ((int) laccess
< ACCESS_COUNT
);
675 return names
[(int) laccess
];
678 static const char *implementationString (const impType imp
)
680 static const char *const names
[] = {
681 "?", "abstract", "virtual", "pure virtual"
683 Assert (sizeof (names
) / sizeof (names
[0]) == IMP_COUNT
);
684 Assert ((int) imp
< IMP_COUNT
);
685 return names
[(int) imp
];
689 * Debugging functions
694 #define boolString(c) ((c) ? "TRUE" : "FALSE")
696 static const char *tokenString (const tokenType type
)
698 static const char *const names
[] = {
699 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
700 "package", "paren-name", "semicolon", "specifier", "*", "[]"
702 Assert (sizeof (names
) / sizeof (names
[0]) == TOKEN_COUNT
);
703 Assert ((int) type
< TOKEN_COUNT
);
704 return names
[(int) type
];
707 static const char *scopeString (const tagScope scope
)
709 static const char *const names
[] = {
710 "global", "static", "extern", "friend", "typedef"
712 Assert (sizeof (names
) / sizeof (names
[0]) == SCOPE_COUNT
);
713 Assert ((int) scope
< SCOPE_COUNT
);
714 return names
[(int) scope
];
717 static const char *declString (const declType declaration
)
719 static const char *const names
[] = {
720 "?", "base", "class", "enum", "event", "signal", "function",
721 "function template", "ignore", "interface", "module", "namespace",
722 "no mangle", "package", "struct", "union",
724 Assert (sizeof (names
) / sizeof (names
[0]) == DECL_COUNT
);
725 Assert ((int) declaration
< DECL_COUNT
);
726 return names
[(int) declaration
];
729 static const char *keywordString (const keywordId keyword
)
731 const size_t count
= sizeof (KeywordTable
) / sizeof (KeywordTable
[0]);
732 const char *name
= "none";
734 for (i
= 0 ; i
< count
; ++i
)
736 const keywordDesc
*p
= &KeywordTable
[i
];
738 if (p
->id
== keyword
)
747 static void UNUSED
pt (tokenInfo
*const token
)
749 if (isType (token
, TOKEN_NAME
))
750 printf("type: %-12s: %-13s line: %lu\n",
751 tokenString (token
->type
), vStringValue (token
->name
),
753 else if (isType (token
, TOKEN_KEYWORD
))
754 printf("type: %-12s: %-13s line: %lu\n",
755 tokenString (token
->type
), keywordString (token
->keyword
),
758 printf("type: %-12s line: %lu\n",
759 tokenString (token
->type
), token
->lineNumber
);
762 static void UNUSED
ps (statementInfo
*const st
)
765 printf("scope: %s decl: %s gotName: %s gotParenName: %s\n",
766 scopeString (st
->scope
), declString (st
->declaration
),
767 boolString (st
->gotName
), boolString (st
->gotParenName
));
768 printf("haveQualifyingName: %s\n", boolString (st
->haveQualifyingName
));
769 printf("access: %s default: %s\n", accessString (st
->member
.access
),
770 accessString (st
->member
.accessDefault
));
772 pt(activeToken (st
));
773 for (i
= 1 ; i
< (unsigned int) NumTokens
; ++i
)
775 printf("prev %u : ", i
);
776 pt(prevToken (st
, i
));
785 * Statement management
788 static boolean
isDataTypeKeyword (const tokenInfo
*const token
)
790 switch (token
->keyword
)
792 case KEYWORD_BOOLEAN
:
801 case KEYWORD_WCHAR_T
:
810 static boolean
isVariableKeyword (const tokenInfo
*const token
)
812 switch (token
->keyword
)
816 case KEYWORD_REGISTER
:
818 case KEYWORD_VIRTUAL
:
820 case KEYWORD_UNSIGNED
:
828 static boolean
isContextualKeyword (const tokenInfo
*const token
)
831 switch (token
->keyword
)
835 case KEYWORD_INTERFACE
:
836 case KEYWORD_NAMESPACE
:
853 static boolean
isContextualStatement (const statementInfo
*const st
)
855 boolean result
= FALSE
;
859 if (isLanguage (Lang_vala
))
861 /* All can be a contextual statement as properties can be of any type */
866 switch (st
->declaration
)
890 static boolean
isMember (const statementInfo
*const st
)
893 if (isType (st
->context
, TOKEN_NAME
))
896 result
= isContextualStatement (st
->parent
);
900 static void initMemberInfo (statementInfo
*const st
)
902 accessType accessDefault
= ACCESS_UNDEFINED
;
904 if (st
->parent
!= NULL
) switch (st
->parent
->declaration
)
909 accessDefault
= ACCESS_UNDEFINED
;
914 if (isLanguage (Lang_java
))
915 accessDefault
= ACCESS_DEFAULT
;
917 accessDefault
= ACCESS_PRIVATE
;
924 accessDefault
= ACCESS_PUBLIC
;
930 st
->member
.accessDefault
= accessDefault
;
931 st
->member
.access
= accessDefault
;
934 static void reinitStatement (statementInfo
*const st
, const boolean partial
)
940 st
->scope
= SCOPE_GLOBAL
;
941 if (isContextualStatement (st
->parent
))
942 st
->declaration
= DECL_BASE
;
944 st
->declaration
= DECL_NONE
;
946 st
->gotParenName
= FALSE
;
947 st
->implementation
= IMP_DEFAULT
;
951 st
->haveQualifyingName
= FALSE
;
952 st
->argEndPosition
= 0;
955 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
957 initToken (st
->token
[i
]);
960 initToken (st
->context
);
961 initToken (st
->blockName
);
962 vStringClear (st
->parentClasses
);
964 /* Init member info. */
966 st
->member
.access
= st
->member
.accessDefault
;
968 /* Init first token */
970 initToken(st
->firstToken
);
973 static void reinitStatementWithToken (statementInfo
*const st
,
974 tokenInfo
*token
, const boolean partial
)
976 tokenInfo
*const save
= newToken ();
977 /* given token can be part of reinit statementInfo */
978 copyToken (save
, token
);
979 reinitStatement (st
, partial
);
980 token
= activeToken (st
);
981 copyToken (token
, save
);
983 ++st
->tokenIndex
; /* this is quite safe because current tokenIndex = 0 */
986 static void initStatement (statementInfo
*const st
, statementInfo
*const parent
)
990 reinitStatement (st
, FALSE
);
993 const tokenInfo
*const src
= activeToken (parent
);
994 tokenInfo
*const dst
= activeToken (st
);
995 copyToken (dst
, src
);
1001 * Tag generation functions
1003 static cKind
cTagKind (const tagType type
)
1005 cKind result
= CK_UNDEFINED
;
1008 case TAG_CLASS
: result
= CK_CLASS
; break;
1009 case TAG_ENUM
: result
= CK_ENUMERATION
; break;
1010 case TAG_ENUMERATOR
: result
= CK_ENUMERATOR
; break;
1011 case TAG_FUNCTION
: result
= CK_FUNCTION
; break;
1012 case TAG_MEMBER
: result
= CK_MEMBER
; break;
1013 case TAG_NAMESPACE
: result
= CK_NAMESPACE
; break;
1014 case TAG_PROTOTYPE
: result
= CK_PROTOTYPE
; break;
1015 case TAG_STRUCT
: result
= CK_STRUCT
; break;
1016 case TAG_TYPEDEF
: result
= CK_TYPEDEF
; break;
1017 case TAG_UNION
: result
= CK_UNION
; break;
1018 case TAG_VARIABLE
: result
= CK_VARIABLE
; break;
1019 case TAG_EXTERN_VAR
: result
= CK_EXTERN_VARIABLE
; break;
1021 default: Assert ("Bad C tag type" == NULL
); break;
1026 static csharpKind
csharpTagKind (const tagType type
)
1028 csharpKind result
= CSK_UNDEFINED
;
1031 case TAG_CLASS
: result
= CSK_CLASS
; break;
1032 case TAG_ENUM
: result
= CSK_ENUMERATION
; break;
1033 case TAG_ENUMERATOR
: result
= CSK_ENUMERATOR
; break;
1034 case TAG_EVENT
: result
= CSK_EVENT
; break;
1035 case TAG_FIELD
: result
= CSK_FIELD
; break;
1036 case TAG_INTERFACE
: result
= CSK_INTERFACE
; break;
1037 case TAG_LOCAL
: result
= CSK_LOCAL
; break;
1038 case TAG_METHOD
: result
= CSK_METHOD
; break;
1039 case TAG_NAMESPACE
: result
= CSK_NAMESPACE
; break;
1040 case TAG_PROPERTY
: result
= CSK_PROPERTY
; break;
1041 case TAG_STRUCT
: result
= CSK_STRUCT
; break;
1042 case TAG_TYPEDEF
: result
= CSK_TYPEDEF
; break;
1044 default: Assert ("Bad C# tag type" == NULL
); break;
1049 static dKind
dTagKind (const tagType type
)
1051 dKind result
= DK_UNDEFINED
;
1054 case TAG_CLASS
: result
= DK_CLASS
; break;
1055 case TAG_ENUM
: result
= DK_ENUMERATION
; break;
1056 case TAG_ENUMERATOR
: result
= DK_ENUMERATOR
; break;
1057 case TAG_FUNCTION
: result
= DK_FUNCTION
; break;
1058 case TAG_INTERFACE
: result
= DK_INTERFACE
; break;
1059 case TAG_MEMBER
: result
= DK_MEMBER
; break;
1060 case TAG_NAMESPACE
: result
= DK_NAMESPACE
; break;
1061 case TAG_PROTOTYPE
: result
= DK_PROTOTYPE
; break;
1062 case TAG_STRUCT
: result
= DK_STRUCT
; break;
1063 case TAG_TYPEDEF
: result
= DK_TYPEDEF
; break;
1064 case TAG_UNION
: result
= DK_UNION
; break;
1065 case TAG_VARIABLE
: result
= DK_VARIABLE
; break;
1066 case TAG_EXTERN_VAR
: result
= DK_EXTERN_VARIABLE
; break;
1068 default: Assert ("Bad D tag type" == NULL
); break;
1073 static valaKind
valaTagKind (const tagType type
)
1075 valaKind result
= VK_UNDEFINED
;
1078 case TAG_CLASS
: result
= VK_CLASS
; break;
1079 case TAG_ENUM
: result
= VK_ENUMERATION
; break;
1080 case TAG_ENUMERATOR
: result
= VK_ENUMERATOR
; break;
1081 case TAG_SIGNAL
: result
= VK_SIGNAL
; break;
1082 case TAG_FIELD
: result
= VK_FIELD
; break;
1083 case TAG_INTERFACE
: result
= VK_INTERFACE
; break;
1084 case TAG_LOCAL
: result
= VK_LOCAL
; break;
1085 case TAG_METHOD
: result
= VK_METHOD
; break;
1086 case TAG_NAMESPACE
: result
= VK_NAMESPACE
; break;
1087 case TAG_PROPERTY
: result
= VK_PROPERTY
; break;
1088 case TAG_STRUCT
: result
= VK_STRUCT
; break;
1090 default: Assert ("Bad Vala tag type" == NULL
); break;
1095 static javaKind
javaTagKind (const tagType type
)
1097 javaKind result
= JK_UNDEFINED
;
1100 case TAG_CLASS
: result
= JK_CLASS
; break;
1101 case TAG_FIELD
: result
= JK_FIELD
; break;
1102 case TAG_INTERFACE
: result
= JK_INTERFACE
; break;
1103 case TAG_METHOD
: result
= JK_METHOD
; break;
1104 case TAG_PACKAGE
: result
= JK_PACKAGE
; break;
1105 case TAG_ENUM
: result
= JK_ENUMERATION
; break;
1106 case TAG_ENUMERATOR
: result
= JK_ENUMERATOR
; break;
1108 default: Assert ("Bad Java tag type" == NULL
); break;
1113 static const char *tagName (const tagType type
)
1116 if (isLanguage (Lang_java
))
1117 result
= JavaKinds
[javaTagKind (type
)].name
;
1118 else if (isLanguage (Lang_csharp
))
1119 result
= CsharpKinds
[csharpTagKind (type
)].name
;
1120 else if (isLanguage (Lang_d
))
1121 result
= DKinds
[dTagKind (type
)].name
;
1122 else if (isLanguage (Lang_vala
))
1123 result
= ValaKinds
[valaTagKind (type
)].name
;
1125 result
= CKinds
[cTagKind (type
)].name
;
1129 static int tagLetter (const tagType type
)
1132 if (isLanguage (Lang_csharp
))
1133 result
= CsharpKinds
[csharpTagKind (type
)].letter
;
1134 else if (isLanguage (Lang_d
))
1135 result
= DKinds
[dTagKind (type
)].letter
;
1136 else if (isLanguage (Lang_java
))
1137 result
= JavaKinds
[javaTagKind (type
)].letter
;
1138 else if (isLanguage (Lang_vala
))
1139 result
= ValaKinds
[valaTagKind (type
)].letter
;
1141 result
= CKinds
[cTagKind (type
)].letter
;
1146 static boolean includeTag (const tagType type, const boolean isFileScope)
1149 if (isFileScope && ! Option.include.fileScope)
1151 else if (isLanguage (Lang_java))
1152 result = JavaKinds [javaTagKind (type)].enabled;
1154 result = CKinds [cTagKind (type)].enabled;
1159 static tagType
declToTagType (const declType declaration
)
1161 tagType type
= TAG_UNDEFINED
;
1163 switch (declaration
)
1165 case DECL_CLASS
: type
= TAG_CLASS
; break;
1166 case DECL_ENUM
: type
= TAG_ENUM
; break;
1167 case DECL_FUNCTION
: type
= TAG_FUNCTION
; break;
1168 case DECL_FUNCTION_TEMPLATE
: type
= TAG_FUNCTION
; break;
1169 case DECL_INTERFACE
:type
= TAG_INTERFACE
; break;
1170 case DECL_NAMESPACE
:type
= TAG_NAMESPACE
; break;
1171 case DECL_STRUCT
: type
= TAG_STRUCT
; break;
1172 case DECL_UNION
: type
= TAG_UNION
; break;
1174 default: Assert ("Unexpected declaration" == NULL
); break;
1179 static const char* accessField (const statementInfo
*const st
)
1181 const char* result
= NULL
;
1183 if ((isLanguage (Lang_cpp
) || isLanguage (Lang_d
) || isLanguage (Lang_ferite
)) &&
1184 st
->scope
== SCOPE_FRIEND
)
1186 else if (st
->member
.access
!= ACCESS_UNDEFINED
)
1187 result
= accessString (st
->member
.access
);
1191 static void addOtherFields (tagEntryInfo
* const tag
, const tagType type
,
1192 const tokenInfo
*const nameToken
,
1193 const statementInfo
*const st
, vString
*const scope
)
1195 /* For selected tag types, append an extension flag designating the
1196 * parent object in which the tag is defined.
1205 case TAG_ENUMERATOR
:
1216 if (vStringLength (scope
) > 0 &&
1217 (isMember (st
) || st
->parent
->declaration
== DECL_NAMESPACE
))
1219 if (isType (st
->context
, TOKEN_NAME
))
1220 tag
->extensionFields
.scope
[0] = tagName (TAG_CLASS
);
1222 tag
->extensionFields
.scope
[0] =
1223 tagName (declToTagType (parentDecl (st
)));
1224 tag
->extensionFields
.scope
[1] = vStringValue (scope
);
1226 if ((type
== TAG_CLASS
|| type
== TAG_INTERFACE
||
1227 type
== TAG_STRUCT
) && vStringLength (st
->parentClasses
) > 0)
1229 tag
->extensionFields
.inheritance
=
1230 vStringValue (st
->parentClasses
);
1232 if (st
->implementation
!= IMP_DEFAULT
&&
1233 (isLanguage (Lang_cpp
) || isLanguage (Lang_csharp
) || isLanguage (Lang_vala
) ||
1234 isLanguage (Lang_java
) || isLanguage (Lang_d
) || isLanguage (Lang_ferite
)))
1236 tag
->extensionFields
.implementation
=
1237 implementationString (st
->implementation
);
1241 tag
->extensionFields
.access
= accessField (st
);
1243 if ((TRUE
== st
->gotArgs
) && (TRUE
== Option
.extensionFields
.argList
) &&
1244 ((TAG_FUNCTION
== type
) || (TAG_METHOD
== type
) || (TAG_PROTOTYPE
== type
)))
1246 tag
->extensionFields
.signature
= getArglistFromFilePos(
1247 tag
->filePosition
, tag
->name
);
1253 if ((TAG_FIELD
== type
) || (TAG_MEMBER
== type
) ||
1254 (TAG_EXTERN_VAR
== type
) || (TAG_TYPEDEF
== type
) ||
1255 (TAG_VARIABLE
== type
) || (TAG_METHOD
== type
) ||
1256 (TAG_PROTOTYPE
== type
) || (TAG_FUNCTION
== type
))
1258 if (((TOKEN_NAME
== st
->firstToken
->type
) || isDataTypeKeyword(st
->firstToken
))
1259 && (0 != strcmp(vStringValue(st
->firstToken
->name
), tag
->name
)))
1261 tag
->extensionFields
.varType
= getVarType(st
, nameToken
);
1266 static const char *getVarType (const statementInfo
*const st
,
1267 const tokenInfo
*const nameToken
)
1269 static vString
*vt
= NULL
;
1271 unsigned int end
= st
->tokenIndex
;
1272 boolean seenType
= FALSE
;
1274 switch (st
->declaration
) {
1277 case DECL_FUNCTION_TEMPLATE
:
1280 return vStringValue(st
->firstToken
->name
);
1288 /* find the end of the type signature in the token list */
1289 for (i
= 0; i
< st
->tokenIndex
; i
++)
1291 const tokenInfo
*const t
= st
->token
[i
];
1293 /* stop if we find the token used to generate the tag name, or
1294 * a name token in the middle yet not preceded by a scope separator */
1295 if ((t
== nameToken
||
1296 (t
->type
== nameToken
->type
&&
1297 t
->keyword
== nameToken
->keyword
&&
1298 t
->lineNumber
== nameToken
->lineNumber
&&
1299 strcmp(vStringValue(t
->name
), vStringValue(nameToken
->name
)) == 0)) ||
1300 (t
->type
== TOKEN_NAME
&& seenType
&&
1301 (i
> 0 && st
->token
[i
- 1]->type
!= TOKEN_DOUBLE_COLON
)))
1305 if (t
->type
!= TOKEN_DOUBLE_COLON
)
1307 if (t
->type
== TOKEN_NAME
)
1309 else if (t
->type
== TOKEN_KEYWORD
&& isDataTypeKeyword(t
))
1313 /* ugly historic workaround when we can't figure out the type */
1314 if (end
< 2 && ! st
->gotArgs
)
1315 return vStringValue(st
->firstToken
->name
);
1317 for (i
= 0; i
< end
; i
++)
1319 tokenInfo
*t
= st
->token
[i
];
1323 case TOKEN_NAME
: /* user typename */
1326 if ((t
->keyword
!= KEYWORD_EXTERN
&& t
->keyword
!= KEYWORD_STATIC
) && /* uninteresting keywords */
1328 /* ignore uninteresting keywords for non-functions */
1329 (t
->keyword
!= KEYWORD_PUBLIC
&&
1330 t
->keyword
!= KEYWORD_PRIVATE
&&
1331 t
->keyword
!= KEYWORD_PROTECTED
&&
1332 t
->keyword
!= KEYWORD_FINAL
&&
1333 t
->keyword
!= KEYWORD_TYPEDEF
&&
1334 /* hack for D static conditions */
1335 t
->keyword
!= KEYWORD_IF
)))
1340 case TOKEN_STAR
: vStringCatS(vt
, " *"); continue;
1341 case TOKEN_ARRAY
: vStringCatS(vt
, "[]"); continue;
1342 case TOKEN_DOUBLE_COLON
:
1343 vStringCatS(vt
, "::");
1347 if (vStringLength(vt
) > 0)
1348 if (isalpha(vStringValue(vt
)[vStringLength(vt
) - 1]))
1349 vStringPut(vt
, ' ');
1350 vStringCat(vt
, t
->name
);
1352 vStringTerminate(vt
);
1353 return vStringValue(vt
);
1356 static void addContextSeparator (vString
*const scope
)
1358 if (isLanguage (Lang_c
) || isLanguage (Lang_cpp
))
1359 vStringCatS (scope
, "::");
1360 else if (isLanguage (Lang_java
) || isLanguage (Lang_d
) || isLanguage (Lang_ferite
) ||
1361 isLanguage (Lang_csharp
) || isLanguage (Lang_vala
))
1362 vStringCatS (scope
, ".");
1365 static void findScopeHierarchy (vString
*const string
,
1366 const statementInfo
*const st
)
1368 const char* const anon
= "<anonymous>";
1369 boolean nonAnonPresent
= FALSE
;
1371 vStringClear (string
);
1372 if (isType (st
->context
, TOKEN_NAME
))
1374 vStringCopy (string
, st
->context
->name
);
1375 nonAnonPresent
= TRUE
;
1377 if (st
->parent
!= NULL
)
1379 vString
*temp
= vStringNew ();
1380 const statementInfo
*s
;
1382 for (s
= st
->parent
; s
!= NULL
; s
= s
->parent
)
1384 if (isContextualStatement (s
) ||
1385 s
->declaration
== DECL_NAMESPACE
)
1387 vStringCopy (temp
, string
);
1388 vStringClear (string
);
1389 if (isType (s
->blockName
, TOKEN_NAME
))
1391 if (isType (s
->context
, TOKEN_NAME
) &&
1392 vStringLength (s
->context
->name
) > 0)
1394 vStringCat (string
, s
->context
->name
);
1395 addContextSeparator (string
);
1397 vStringCat (string
, s
->blockName
->name
);
1398 nonAnonPresent
= TRUE
;
1401 vStringCopyS (string
, anon
);
1402 if (vStringLength (temp
) > 0)
1403 addContextSeparator (string
);
1404 vStringCat (string
, temp
);
1407 vStringDelete (temp
);
1409 if (! nonAnonPresent
)
1410 vStringClear (string
);
1414 static void makeExtraTagEntry (const tagType type
, tagEntryInfo
*const e
,
1415 vString
*const scope
)
1417 if (Option
.include
.qualifiedTags
&&
1418 scope
!= NULL
&& vStringLength (scope
) > 0)
1420 vString
*const scopedName
= vStringNew ();
1422 if (type
!= TAG_ENUMERATOR
)
1423 vStringCopy (scopedName
, scope
);
1426 /* remove last component (i.e. enumeration name) from scope */
1427 const char* const sc
= vStringValue (scope
);
1428 const char* colon
= strrchr (sc
, ':');
1431 while (*colon
== ':' && colon
> sc
)
1433 vStringNCopy (scopedName
, scope
, colon
+ 1 - sc
);
1436 if (vStringLength (scopedName
) > 0)
1438 addContextSeparator (scopedName
);
1439 vStringCatS (scopedName
, e
->name
);
1440 e
->name
= vStringValue (scopedName
);
1443 vStringDelete (scopedName
);
1447 static void makeTag (const tokenInfo
*const token
,
1448 const statementInfo
*const st
,
1449 boolean isFileScope
, const tagType type
)
1453 fprintf(stderr
, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
1456 /* Nothing is really of file scope when it appears in a header file.
1458 isFileScope
= (boolean
) (isFileScope
&& ! isHeaderFile ());
1460 if (isType (token
, TOKEN_NAME
) && vStringLength (token
->name
) > 0 /* &&
1461 includeTag (type, isFileScope) */)
1463 vString
*scope
= vStringNew ();
1466 /* take only functions which are introduced by "function ..." */
1467 if (type
== TAG_FUNCTION
&& isLanguage (Lang_ferite
) &&
1468 strncmp("function", st
->firstToken
->name
->buffer
, 8) != 0)
1473 initTagEntry (&e
, vStringValue (token
->name
));
1475 e
.lineNumber
= token
->lineNumber
;
1476 e
.filePosition
= token
->filePosition
;
1477 e
.isFileScope
= isFileScope
;
1478 e
.kindName
= tagName (type
);
1479 e
.kind
= tagLetter (type
);
1481 findScopeHierarchy (scope
, st
);
1482 addOtherFields (&e
, type
, token
, st
, scope
);
1488 if (NULL
!= TagEntryFunction
)
1489 makeExtraTagEntry (type
, &e
, scope
);
1490 vStringDelete (scope
);
1491 if (NULL
!= e
.extensionFields
.signature
)
1492 free((char *) e
.extensionFields
.signature
);
1496 static boolean
isValidTypeSpecifier (const declType declaration
)
1499 switch (declaration
)
1516 static void qualifyEnumeratorTag (const statementInfo
*const st
,
1517 const tokenInfo
*const nameToken
)
1519 if (isType (nameToken
, TOKEN_NAME
))
1520 makeTag (nameToken
, st
, TRUE
, TAG_ENUMERATOR
);
1523 static void qualifyFunctionTag (const statementInfo
*const st
,
1524 const tokenInfo
*const nameToken
)
1526 if (isType (nameToken
, TOKEN_NAME
))
1528 const tagType type
= (isLanguage (Lang_java
) || isLanguage (Lang_csharp
) || isLanguage (Lang_vala
))
1529 ? TAG_METHOD
: TAG_FUNCTION
;
1530 const boolean isFileScope
=
1531 (boolean
) (st
->member
.access
== ACCESS_PRIVATE
||
1532 (!isMember (st
) && st
->scope
== SCOPE_STATIC
));
1534 makeTag (nameToken
, st
, isFileScope
, type
);
1538 static void qualifyFunctionDeclTag (const statementInfo
*const st
,
1539 const tokenInfo
*const nameToken
)
1541 if (! isType (nameToken
, TOKEN_NAME
))
1543 else if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
) || isLanguage (Lang_vala
))
1544 qualifyFunctionTag (st
, nameToken
);
1545 else if (st
->scope
== SCOPE_TYPEDEF
)
1546 makeTag (nameToken
, st
, TRUE
, TAG_TYPEDEF
);
1547 else if (isValidTypeSpecifier (st
->declaration
) &&
1548 ! (isLanguage (Lang_csharp
) || isLanguage (Lang_vala
)))
1549 makeTag (nameToken
, st
, TRUE
, TAG_PROTOTYPE
);
1552 static void qualifyCompoundTag (const statementInfo
*const st
,
1553 const tokenInfo
*const nameToken
)
1555 if (isType (nameToken
, TOKEN_NAME
))
1557 const tagType type
= declToTagType (st
->declaration
);
1559 if (type
!= TAG_UNDEFINED
)
1560 makeTag (nameToken
, st
, (boolean
) (! isLanguage (Lang_java
) &&
1561 ! isLanguage (Lang_csharp
) &&
1562 ! isLanguage (Lang_vala
)), type
);
1566 static void qualifyBlockTag (statementInfo
*const st
,
1567 const tokenInfo
*const nameToken
)
1569 switch (st
->declaration
)
1573 case DECL_INTERFACE
:
1574 case DECL_NAMESPACE
:
1577 qualifyCompoundTag (st
, nameToken
);
1583 static void qualifyVariableTag (const statementInfo
*const st
,
1584 const tokenInfo
*const nameToken
)
1586 /* We have to watch that we do not interpret a declaration of the
1587 * form "struct tag;" as a variable definition. In such a case, the
1588 * token preceding the name will be a keyword.
1590 if (! isType (nameToken
, TOKEN_NAME
))
1592 else if (st
->declaration
== DECL_IGNORE
)
1594 else if (st
->scope
== SCOPE_TYPEDEF
)
1595 makeTag (nameToken
, st
, TRUE
, TAG_TYPEDEF
);
1596 else if (st
->declaration
== DECL_PACKAGE
)
1597 makeTag (nameToken
, st
, FALSE
, TAG_PACKAGE
);
1598 else if (st
->declaration
== DECL_MODULE
) /* handle modules in D as namespaces */
1599 makeTag (nameToken
, st
, FALSE
, TAG_NAMESPACE
);
1600 else if (isValidTypeSpecifier (st
->declaration
))
1604 if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
) || isLanguage (Lang_vala
))
1605 makeTag (nameToken
, st
, (boolean
) (st
->member
.access
== ACCESS_PRIVATE
), TAG_FIELD
);
1606 else if (st
->scope
== SCOPE_GLOBAL
|| st
->scope
== SCOPE_STATIC
)
1607 makeTag (nameToken
, st
, TRUE
, TAG_MEMBER
);
1609 else if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
) || isLanguage (Lang_vala
))
1613 if (st
->scope
== SCOPE_EXTERN
|| ! st
->haveQualifyingName
)
1614 makeTag (nameToken
, st
, FALSE
, TAG_EXTERN_VAR
);
1616 makeTag (nameToken
, st
, (boolean
) (st
->scope
== SCOPE_STATIC
), TAG_VARIABLE
);
1625 static int skipToOneOf (const char *const chars
)
1630 while (c
!= EOF
&& c
!= '\0' && strchr (chars
, c
) == NULL
);
1635 /* Skip to the next non-white character.
1637 static int skipToNonWhite (void)
1645 while (isspace (c
));
1650 /* Skips to the next brace in column 1. This is intended for cases where
1651 * preprocessor constructs result in unbalanced braces.
1653 static void skipToFormattedBraceMatch (void)
1659 while (c
!= EOF
&& (c
!= '\n' || next
!= '}'))
1666 /* Skip to the matching character indicated by the pair string. If skipping
1667 * to a matching brace and any brace is found within a different level of a
1668 * #if conditional statement while brace formatting is in effect, we skip to
1669 * the brace matched by its formatting. It is assumed that we have already
1670 * read the character which starts the group (i.e. the first character of
1673 static void skipToMatch (const char *const pair
)
1675 const boolean braceMatching
= (boolean
) (strcmp ("{}", pair
) == 0);
1676 const boolean braceFormatting
= (boolean
) (isBraceFormat () && braceMatching
);
1677 const unsigned int initialLevel
= getDirectiveNestLevel ();
1678 const int begin
= pair
[0], end
= pair
[1];
1679 const unsigned long inputLineNumber
= getInputLineNumber ();
1682 if (isLanguage(Lang_d
) && pair
[0] == '<')
1683 return; /* ignore e.g. Foo!(x < 2) */
1684 while (matchLevel
> 0 && (c
= cppGetc ()) != EOF
)
1689 if (braceFormatting
&& getDirectiveNestLevel () != initialLevel
)
1691 skipToFormattedBraceMatch ();
1698 if (braceFormatting
&& getDirectiveNestLevel () != initialLevel
)
1700 skipToFormattedBraceMatch ();
1704 /* early out if matching "<>" and we encounter a ";" or "{" to mitigate
1705 * match problems with C++ generics containing a static expression like
1707 * normally neither ";" nor "{" could appear inside "<>" anyway. */
1708 else if (isLanguage (Lang_cpp
) && begin
== '<' &&
1709 (c
== ';' || c
== '{'))
1717 verbose ("%s: failed to find match for '%c' at line %lu\n",
1718 getInputFileName (), begin
, inputLineNumber
);
1720 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
1722 longjmp (Exception
, (int) ExceptionFormattingError
);
1726 static void skipParens (void)
1728 const int c
= skipToNonWhite ();
1736 static void skipBraces (void)
1738 const int c
= skipToNonWhite ();
1746 static keywordId
analyzeKeyword (const char *const name
)
1748 const keywordId id
= (keywordId
) lookupKeyword (name
, getSourceLanguage ());
1750 /* ignore D @attributes and Java @annotations(...), but show them in function signatures */
1751 if ((isLanguage(Lang_d
) || isLanguage(Lang_java
)) && id
== KEYWORD_NONE
&& name
[0] == '@')
1753 skipParens(); /* if annotation has parameters, skip them */
1754 return KEYWORD_CONST
;
1759 static void analyzeIdentifier (tokenInfo
*const token
)
1761 char *const name
= vStringValue (token
->name
);
1762 const char *replacement
= NULL
;
1763 boolean parensToo
= FALSE
;
1765 if (isLanguage (Lang_java
) ||
1766 ! isIgnoreToken (name
, &parensToo
, &replacement
))
1768 if (replacement
!= NULL
)
1769 token
->keyword
= analyzeKeyword (replacement
);
1771 token
->keyword
= analyzeKeyword (vStringValue (token
->name
));
1773 if (token
->keyword
== KEYWORD_NONE
)
1774 token
->type
= TOKEN_NAME
;
1776 token
->type
= TOKEN_KEYWORD
;
1783 int c
= skipToNonWhite ();
1791 static void readIdentifier (tokenInfo
*const token
, const int firstChar
)
1793 vString
*const name
= token
->name
;
1798 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1799 * the ~ and the class name. */
1800 if (isLanguage (Lang_cpp
) && firstChar
== '~')
1802 vStringPut (name
, c
);
1803 c
= skipToNonWhite ();
1808 vStringPut (name
, c
);
1810 } while (isident (c
) || (isLanguage (Lang_vala
) && '.' == c
));
1811 vStringTerminate (name
);
1812 cppUngetc (c
); /* unget non-identifier character */
1814 /* Vala supports '?' at end of a type (with or without whitespace before) for nullable types */
1815 if (isLanguage (Lang_vala
))
1817 c
= skipToNonWhite ();
1819 vStringPut (name
, c
);
1824 analyzeIdentifier (token
);
1827 static void readPackageName (tokenInfo
*const token
, const int firstChar
)
1829 vString
*const name
= token
->name
;
1834 while (isident (c
) || c
== '.')
1836 vStringPut (name
, c
);
1839 vStringTerminate (name
);
1840 cppUngetc (c
); /* unget non-package character */
1843 static void readPackageOrNamespace (statementInfo
*const st
, const declType declaration
)
1845 st
->declaration
= declaration
;
1847 if (declaration
== DECL_NAMESPACE
&& !(isLanguage (Lang_csharp
) || isLanguage (Lang_vala
)))
1849 /* In C++ a namespace is specified one level at a time. */
1854 /* In C#, a namespace can also be specified like a Java package name. */
1855 tokenInfo
*const token
= activeToken (st
);
1856 Assert (isType (token
, TOKEN_KEYWORD
));
1857 readPackageName (token
, skipToNonWhite ());
1858 token
->type
= TOKEN_NAME
;
1860 st
->haveQualifyingName
= TRUE
;
1864 static void readPackage (statementInfo
*const st
)
1866 tokenInfo
*const token
= activeToken (st
);
1867 Assert (isType (token
, TOKEN_KEYWORD
));
1868 readPackageName (token
, skipToNonWhite ());
1869 token
->type
= TOKEN_NAME
;
1870 if (isLanguage (Lang_d
))
1871 st
->declaration
= DECL_MODULE
;
1873 st
->declaration
= DECL_PACKAGE
;
1875 st
->haveQualifyingName
= TRUE
;
1878 static void processName (statementInfo
*const st
)
1880 Assert (isType (activeToken (st
), TOKEN_NAME
));
1881 if (st
->gotName
&& st
->declaration
== DECL_NONE
)
1882 st
->declaration
= DECL_BASE
;
1884 st
->haveQualifyingName
= TRUE
;
1887 static void readOperator (statementInfo
*const st
)
1889 const char *const acceptable
= "+-*/%^&|~!=<>,[]";
1890 const tokenInfo
* const prev
= prevToken (st
,1);
1891 tokenInfo
*const token
= activeToken (st
);
1892 vString
*const name
= token
->name
;
1893 int c
= skipToNonWhite ();
1895 /* When we arrive here, we have the keyword "operator" in 'name'.
1897 if (isType (prev
, TOKEN_KEYWORD
) && (prev
->keyword
== KEYWORD_ENUM
||
1898 prev
->keyword
== KEYWORD_STRUCT
|| prev
->keyword
== KEYWORD_UNION
))
1899 ; /* ignore "operator" keyword if preceded by these keywords */
1902 /* Verify whether this is a valid function call (i.e. "()") operator.
1904 if (cppGetc () == ')')
1906 vStringPut (name
, ' '); /* always separate operator from keyword */
1907 c
= skipToNonWhite ();
1909 vStringCatS (name
, "()");
1917 else if (isident1 (c
))
1919 /* Handle "new" and "delete" operators, and conversion functions
1920 * (per 13.3.1.1.2 [2] of the C++ spec).
1922 boolean whiteSpace
= TRUE
; /* default causes insertion of space */
1931 vStringPut (name
, ' ');
1934 vStringPut (name
, c
);
1937 } while (! isOneOf (c
, "(;") && c
!= EOF
);
1938 vStringTerminate (name
);
1940 else if (isOneOf (c
, acceptable
))
1942 vStringPut (name
, ' '); /* always separate operator from keyword */
1945 vStringPut (name
, c
);
1947 } while (isOneOf (c
, acceptable
));
1948 vStringTerminate (name
);
1953 token
->type
= TOKEN_NAME
;
1954 token
->keyword
= KEYWORD_NONE
;
1958 static void copyToken (tokenInfo
*const dest
, const tokenInfo
*const src
)
1960 dest
->type
= src
->type
;
1961 dest
->keyword
= src
->keyword
;
1962 dest
->filePosition
= src
->filePosition
;
1963 dest
->lineNumber
= src
->lineNumber
;
1964 vStringCopy (dest
->name
, src
->name
);
1967 static void setAccess (statementInfo
*const st
, const accessType laccess
)
1971 if (isLanguage (Lang_cpp
) || isLanguage (Lang_d
) || isLanguage (Lang_ferite
))
1973 int c
= skipToNonWhite ();
1976 reinitStatementWithToken (st
, prevToken (st
, 1), FALSE
);
1980 st
->member
.accessDefault
= laccess
;
1982 st
->member
.access
= laccess
;
1986 static void discardTypeList (tokenInfo
*const token
)
1988 int c
= skipToNonWhite ();
1989 while (isident1 (c
))
1991 readIdentifier (token
, c
);
1992 c
= skipToNonWhite ();
1993 if (c
== '.' || c
== ',')
1994 c
= skipToNonWhite ();
1999 static void addParentClass (statementInfo
*const st
, tokenInfo
*const token
)
2001 if (vStringLength (token
->name
) > 0 &&
2002 vStringLength (st
->parentClasses
) > 0)
2004 vStringPut (st
->parentClasses
, ',');
2006 vStringCat (st
->parentClasses
, token
->name
);
2009 static void readParents (statementInfo
*const st
, const int qualifier
)
2011 tokenInfo
*const token
= newToken ();
2012 tokenInfo
*const parent
= newToken ();
2017 c
= skipToNonWhite ();
2020 readIdentifier (token
, c
);
2021 if (isType (token
, TOKEN_NAME
))
2022 vStringCat (parent
->name
, token
->name
);
2025 addParentClass (st
, parent
);
2029 else if (c
== qualifier
)
2030 vStringPut (parent
->name
, c
);
2033 else if (isType (token
, TOKEN_NAME
))
2035 addParentClass (st
, parent
);
2038 } while (c
!= '{' && c
!= EOF
);
2040 deleteToken (parent
);
2041 deleteToken (token
);
2044 static void checkIsClassEnum (statementInfo
*const st
, const declType decl
)
2046 if (! isLanguage (Lang_cpp
) || st
->declaration
!= DECL_ENUM
)
2047 st
->declaration
= decl
;
2050 static void processToken (tokenInfo
*const token
, statementInfo
*const st
)
2052 switch (token
->keyword
) /* is it a reserved word? */
2056 case KEYWORD_NONE
: processName (st
); break;
2057 case KEYWORD_ABSTRACT
: st
->implementation
= IMP_ABSTRACT
; break;
2058 case KEYWORD_ATTRIBUTE
: skipParens (); initToken (token
); break;
2059 case KEYWORD_CATCH
: skipParens (); skipBraces (); break;
2060 case KEYWORD_CHAR
: st
->declaration
= DECL_BASE
; break;
2061 case KEYWORD_CLASS
: checkIsClassEnum (st
, DECL_CLASS
); break;
2062 case KEYWORD_CONST
: st
->declaration
= DECL_BASE
; break;
2063 case KEYWORD_DOUBLE
: st
->declaration
= DECL_BASE
; break;
2064 case KEYWORD_ENUM
: st
->declaration
= DECL_ENUM
; break;
2065 case KEYWORD_EXTENDS
: readParents (st
, '.');
2066 setToken (st
, TOKEN_NONE
); break;
2067 case KEYWORD_FLOAT
: st
->declaration
= DECL_BASE
; break;
2068 case KEYWORD_FRIEND
: st
->scope
= SCOPE_FRIEND
; break;
2069 case KEYWORD_IMPLEMENTS
:readParents (st
, '.');
2070 setToken (st
, TOKEN_NONE
); break;
2071 case KEYWORD_IMPORT
: st
->declaration
= DECL_IGNORE
; break;
2072 case KEYWORD_INT
: st
->declaration
= DECL_BASE
; break;
2073 case KEYWORD_BOOLEAN
: st
->declaration
= DECL_BASE
; break;
2074 case KEYWORD_WCHAR_T
: st
->declaration
= DECL_BASE
; break;
2075 case KEYWORD_SIZE_T
: st
->declaration
= DECL_BASE
; break;
2076 case KEYWORD_INTERFACE
: st
->declaration
= DECL_INTERFACE
; break;
2077 case KEYWORD_LONG
: st
->declaration
= DECL_BASE
; break;
2078 case KEYWORD_OPERATOR
: readOperator (st
); break;
2079 case KEYWORD_MODULE
: readPackage (st
); break;
2080 case KEYWORD_PRIVATE
: setAccess (st
, ACCESS_PRIVATE
); break;
2081 case KEYWORD_PROTECTED
: setAccess (st
, ACCESS_PROTECTED
); break;
2082 case KEYWORD_PUBLIC
: setAccess (st
, ACCESS_PUBLIC
); break;
2083 case KEYWORD_SHORT
: st
->declaration
= DECL_BASE
; break;
2084 case KEYWORD_SIGNED
: st
->declaration
= DECL_BASE
; break;
2085 case KEYWORD_STRUCT
: checkIsClassEnum (st
, DECL_STRUCT
); break;
2086 case KEYWORD_STATIC_ASSERT
: skipParens (); break;
2087 case KEYWORD_THROWS
: discardTypeList (token
); break;
2088 case KEYWORD_TYPEDEF
: st
->scope
= SCOPE_TYPEDEF
; break;
2089 case KEYWORD_UNION
: st
->declaration
= DECL_UNION
; break;
2090 case KEYWORD_UNSIGNED
: st
->declaration
= DECL_BASE
; break;
2091 case KEYWORD_USING
: st
->declaration
= DECL_IGNORE
; break;
2092 case KEYWORD_VOID
: st
->declaration
= DECL_BASE
; break;
2093 case KEYWORD_VOLATILE
: st
->declaration
= DECL_BASE
; break;
2094 case KEYWORD_VIRTUAL
: st
->implementation
= IMP_VIRTUAL
; break;
2096 case KEYWORD_NAMESPACE
: readPackageOrNamespace (st
, DECL_NAMESPACE
); break;
2097 case KEYWORD_PACKAGE
: readPackageOrNamespace (st
, DECL_PACKAGE
); break;
2100 if (isLanguage (Lang_csharp
))
2101 st
->declaration
= DECL_EVENT
;
2104 case KEYWORD_SIGNAL
:
2106 if (isLanguage (Lang_vala
))
2107 st
->declaration
= DECL_SIGNAL
;
2110 case KEYWORD_EXTERN
:
2112 if (! isLanguage (Lang_csharp
) || !st
->gotName
)
2114 /*reinitStatement (st, FALSE);*/
2115 st
->scope
= SCOPE_EXTERN
;
2116 st
->declaration
= DECL_BASE
;
2120 case KEYWORD_STATIC
:
2122 if (! isLanguage (Lang_java
) && ! isLanguage (Lang_csharp
) && ! isLanguage (Lang_vala
))
2124 /*reinitStatement (st, FALSE);*/
2125 st
->scope
= SCOPE_STATIC
;
2126 st
->declaration
= DECL_BASE
;
2131 if (isLanguage (Lang_d
))
2132 { /* static if (is(typeof(__traits(getMember, a, name)) == function)) */
2133 int c
= skipToNonWhite ();
2142 * Parenthesis handling functions
2145 static void restartStatement (statementInfo
*const st
)
2147 tokenInfo
*const save
= newToken ();
2148 tokenInfo
*token
= activeToken (st
);
2150 copyToken (save
, token
);
2151 DebugStatement ( if (debug (DEBUG_PARSE
)) printf ("<ES>");)
2152 reinitStatement (st
, FALSE
);
2153 token
= activeToken (st
);
2154 copyToken (token
, save
);
2156 processToken (token
, st
);
2159 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
2161 * mem-initializer-list:
2162 * mem-initializer, mem-initializer-list
2165 * [::] [nested-name-spec] class-name (...)
2168 static void skipMemIntializerList (tokenInfo
*const token
)
2174 c
= skipToNonWhite ();
2175 while (isident1 (c
) || c
== ':')
2178 readIdentifier (token
, c
);
2179 c
= skipToNonWhite ();
2184 c
= skipToNonWhite ();
2189 c
= skipToNonWhite ();
2195 static void skipMacro (statementInfo
*const st
)
2197 tokenInfo
*const prev2
= prevToken (st
, 2);
2199 if (isType (prev2
, TOKEN_NAME
))
2204 static boolean
isDPostArgumentToken(tokenInfo
*const token
)
2206 switch (token
->keyword
)
2208 /* Note: some other keywords e.g. immutable are parsed as
2209 * KEYWORD_CONST - see initializeDParser */
2211 /* template constraint */
2222 if (vStringValue(token
->name
)[0] == '@')
2227 /* Skips over characters following the parameter list. This will be either
2228 * non-ANSI style function declarations or C++ stuff. Our choices:
2232 * int func (one, two) int one; float two; {...}
2234 * int func (int one, float two);
2235 * int func (int one, float two) {...}
2237 * int foo (...) [const|volatile] [throw (...)];
2238 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2239 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2242 static boolean
skipPostArgumentStuff (statementInfo
*const st
,
2243 parenInfo
*const info
)
2245 tokenInfo
*const token
= activeToken (st
);
2246 unsigned int parameters
= info
->parameterCount
;
2247 unsigned int elementCount
= 0;
2248 boolean restart
= FALSE
;
2249 boolean end
= FALSE
;
2250 int c
= skipToNonWhite ();
2257 case ':': skipMemIntializerList (token
);break; /* ctor-initializer */
2258 case '[': skipToMatch ("[]"); break;
2259 case '=': cppUngetc (c
); end
= TRUE
; break;
2260 case '{': cppUngetc (c
); end
= TRUE
; break;
2261 case '}': cppUngetc (c
); end
= TRUE
; break;
2265 if (elementCount
> 0)
2273 if (parameters
== 0 || elementCount
< 2)
2278 else if (--parameters
== 0)
2287 readIdentifier (token
, c
);
2288 if (isLanguage(Lang_d
) && isDPostArgumentToken(token
))
2289 token
->keyword
= KEYWORD_CONST
;
2291 switch (token
->keyword
)
2293 case KEYWORD_ATTRIBUTE
: skipParens (); break;
2294 case KEYWORD_THROW
: skipParens (); break;
2295 case KEYWORD_CONST
: break;
2296 case KEYWORD_NOEXCEPT
: break;
2297 case KEYWORD_TRY
: break;
2298 case KEYWORD_VOLATILE
: break;
2300 case KEYWORD_CATCH
: case KEYWORD_CLASS
:
2301 case KEYWORD_EXPLICIT
: case KEYWORD_EXTERN
:
2302 case KEYWORD_FRIEND
: case KEYWORD_INLINE
:
2303 case KEYWORD_MUTABLE
: case KEYWORD_NAMESPACE
:
2304 case KEYWORD_NEW
: case KEYWORD_OPERATOR
:
2305 case KEYWORD_OVERLOAD
: case KEYWORD_PRIVATE
:
2306 case KEYWORD_PROTECTED
: case KEYWORD_PUBLIC
:
2307 case KEYWORD_STATIC
: case KEYWORD_TEMPLATE
:
2308 case KEYWORD_TYPEDEF
: case KEYWORD_TYPENAME
:
2309 case KEYWORD_USING
: case KEYWORD_VIRTUAL
:
2310 /* Never allowed within parameter declarations.
2317 /* "override" and "final" are only keywords in the declaration of a virtual
2318 * member function, so need to be handled specially, not as keywords */
2319 if (isLanguage(Lang_cpp
) && isType (token
, TOKEN_NAME
) &&
2320 (strcmp ("override", vStringValue (token
->name
)) == 0 ||
2321 strcmp ("final", vStringValue (token
->name
)) == 0))
2323 else if (isType (token
, TOKEN_NONE
))
2325 else if (info
->isKnrParamList
&& info
->parameterCount
> 0)
2329 /* If we encounter any other identifier immediately
2330 * following an empty parameter list, this is almost
2331 * certainly one of those Microsoft macro "thingies"
2332 * that the automatic source code generation sticks
2333 * in. Terminate the current statement.
2345 c
= skipToNonWhite ();
2352 restartStatement (st
);
2354 setToken (st
, TOKEN_NONE
);
2355 return (boolean
) (c
!= EOF
);
2358 static void skipJavaThrows (statementInfo
*const st
)
2360 tokenInfo
*const token
= activeToken (st
);
2361 int c
= skipToNonWhite ();
2365 readIdentifier (token
, c
);
2366 if (token
->keyword
== KEYWORD_THROWS
)
2370 c
= skipToNonWhite ();
2373 readIdentifier (token
, c
);
2374 c
= skipToNonWhite ();
2376 } while (c
== '.' || c
== ',');
2380 setToken (st
, TOKEN_NONE
);
2383 static void skipValaPostParens (statementInfo
*const st
)
2385 tokenInfo
*const token
= activeToken (st
);
2386 int c
= skipToNonWhite ();
2388 while (isident1 (c
))
2390 readIdentifier (token
, c
);
2391 if (token
->keyword
== KEYWORD_ATTRIBUTE
)
2393 /* parse contracts */
2395 c
= skipToNonWhite ();
2397 else if (token
->keyword
== KEYWORD_THROWS
)
2401 c
= skipToNonWhite ();
2404 readIdentifier (token
, c
);
2405 c
= skipToNonWhite ();
2407 } while (c
== '.' || c
== ',');
2413 setToken (st
, TOKEN_NONE
);
2416 static void analyzePostParens (statementInfo
*const st
, parenInfo
*const info
)
2418 const unsigned long inputLineNumber
= getInputLineNumber ();
2419 int c
= skipToNonWhite ();
2422 if (isOneOf (c
, "{;,="))
2424 else if (isLanguage (Lang_java
))
2425 skipJavaThrows (st
);
2426 else if (isLanguage (Lang_vala
))
2427 skipValaPostParens(st
);
2430 if (! skipPostArgumentStuff (st
, info
))
2433 "%s: confusing argument declarations beginning at line %lu\n",
2434 getInputFileName (), inputLineNumber
);
2435 longjmp (Exception
, (int) ExceptionFormattingError
);
2440 static int parseParens (statementInfo
*const st
, parenInfo
*const info
)
2442 tokenInfo
*const token
= activeToken (st
);
2443 unsigned int identifierCount
= 0;
2444 unsigned int depth
= 1;
2445 boolean firstChar
= TRUE
;
2446 int nextChar
= '\0';
2448 info
->parameterCount
= 1;
2451 int c
= skipToNonWhite ();
2458 /* DEBUG_PRINT("parseParens, po++\n"); */
2459 info
->isKnrParamList
= FALSE
;
2460 if (identifierCount
== 0)
2461 info
->isParamList
= FALSE
;
2467 info
->isKnrParamList
= FALSE
;
2472 info
->isNameCandidate
= FALSE
;
2473 info
->isKnrParamList
= FALSE
;
2478 info
->isNameCandidate
= FALSE
;
2479 if (info
->isKnrParamList
)
2481 ++info
->parameterCount
;
2482 identifierCount
= 0;
2488 info
->isKnrParamList
= FALSE
;
2489 info
->isNameCandidate
= FALSE
;
2492 info
->isParamList
= FALSE
;
2500 info
->isKnrParamList
= FALSE
;
2506 info
->isKnrParamList
= FALSE
;
2513 info
->parameterCount
= 0;
2519 info
->isKnrParamList
= FALSE
;
2522 info
->isNameCandidate
= FALSE
;
2527 else if (isType (token
, TOKEN_PAREN_NAME
))
2529 c
= skipToNonWhite ();
2530 if (c
== '*') /* check for function pointer */
2533 c
= skipToNonWhite ();
2541 info
->nestedArgs
= TRUE
;
2553 if (++identifierCount
> 1)
2554 info
->isKnrParamList
= FALSE
;
2555 readIdentifier (token
, c
);
2556 if (isType (token
, TOKEN_NAME
) && info
->isNameCandidate
)
2557 token
->type
= TOKEN_PAREN_NAME
;
2558 else if (isType (token
, TOKEN_KEYWORD
))
2560 info
->isKnrParamList
= FALSE
;
2561 info
->isNameCandidate
= FALSE
;
2564 else if (isLanguage(Lang_d
) && c
== '!')
2565 { /* D template instantiation */
2566 info
->isNameCandidate
= FALSE
;
2567 info
->isKnrParamList
= FALSE
;
2571 info
->isParamList
= FALSE
;
2572 info
->isKnrParamList
= FALSE
;
2573 info
->isNameCandidate
= FALSE
;
2574 info
->invalidContents
= TRUE
;
2580 } while (! info
->nestedArgs
&& depth
> 0 &&
2581 (info
->isKnrParamList
|| info
->isNameCandidate
));
2583 if (! info
->nestedArgs
) while (depth
> 0)
2588 if (st
->argEndPosition
== 0)
2589 st
->argEndPosition
= mio_tell (File
.mio
);
2591 if (! info
->isNameCandidate
)
2597 static void initParenInfo (parenInfo
*const info
)
2599 info
->isParamList
= TRUE
;
2600 info
->isKnrParamList
= TRUE
;
2601 info
->isNameCandidate
= TRUE
;
2602 info
->invalidContents
= FALSE
;
2603 info
->nestedArgs
= FALSE
;
2604 info
->parameterCount
= 0;
2607 static void analyzeParens (statementInfo
*const st
)
2609 tokenInfo
*const prev
= prevToken (st
, 1);
2611 if (! isType (prev
, TOKEN_NONE
)) /* in case of ignored enclosing macros */
2613 tokenInfo
*const token
= activeToken (st
);
2617 initParenInfo (&info
);
2618 parseParens (st
, &info
);
2620 c
= skipToNonWhite ();
2623 if (info
.invalidContents
)
2625 reinitStatement (st
, FALSE
);
2627 else if (info
.isNameCandidate
&& isType (token
, TOKEN_PAREN_NAME
) &&
2628 ! st
->gotParenName
&&
2629 (! info
.isParamList
|| ! st
->haveQualifyingName
||
2631 (c
== '=' && st
->implementation
!= IMP_VIRTUAL
) ||
2632 (st
->declaration
== DECL_NONE
&& isOneOf (c
, ",;"))))
2634 token
->type
= TOKEN_NAME
;
2636 st
->gotParenName
= TRUE
;
2637 if (isLanguage(Lang_d
) && c
== '(' && isType (prev
, TOKEN_NAME
))
2639 st
->declaration
= DECL_FUNCTION_TEMPLATE
;
2640 copyToken (st
->blockName
, prev
);
2643 else if (! st
->gotArgs
&& info
.isParamList
)
2646 setToken (st
, TOKEN_ARGS
);
2648 analyzePostParens (st
, &info
);
2652 setToken (st
, TOKEN_NONE
);
2658 * Token parsing functions
2661 static void addContext (statementInfo
*const st
, const tokenInfo
* const token
)
2663 if (isType (token
, TOKEN_NAME
))
2665 if (vStringLength (st
->context
->name
) > 0)
2667 if (isLanguage (Lang_c
) || isLanguage (Lang_cpp
))
2668 vStringCatS (st
->context
->name
, "::");
2669 else if (isLanguage (Lang_java
) ||
2670 isLanguage (Lang_d
) || isLanguage (Lang_ferite
) ||
2671 isLanguage (Lang_csharp
) || isLanguage (Lang_vala
))
2672 vStringCatS (st
->context
->name
, ".");
2674 vStringCat (st
->context
->name
, token
->name
);
2675 st
->context
->type
= TOKEN_NAME
;
2679 static boolean
inheritingDeclaration (declType decl
)
2681 /* enum base types */
2682 if (decl
== DECL_ENUM
)
2684 return (boolean
) (isLanguage (Lang_cpp
) || isLanguage (Lang_csharp
) ||
2685 isLanguage (Lang_d
));
2688 decl
== DECL_CLASS
||
2689 decl
== DECL_STRUCT
||
2690 decl
== DECL_INTERFACE
);
2693 static void processColon (statementInfo
*const st
)
2696 const boolean doubleColon
= (boolean
) (c
== ':');
2700 setToken (st
, TOKEN_DOUBLE_COLON
);
2701 st
->haveQualifyingName
= FALSE
;
2706 if ((isLanguage (Lang_cpp
) || isLanguage (Lang_csharp
) || isLanguage (Lang_d
) ||
2707 isLanguage (Lang_vala
)) &&
2708 inheritingDeclaration (st
->declaration
))
2710 readParents (st
, ':');
2712 else if (parentDecl (st
) == DECL_STRUCT
|| parentDecl (st
) == DECL_CLASS
)
2714 c
= skipToOneOf (",;");
2716 setToken (st
, TOKEN_COMMA
);
2718 setToken (st
, TOKEN_SEMICOLON
);
2722 const tokenInfo
*const prev
= prevToken (st
, 1);
2723 const tokenInfo
*const prev2
= prevToken (st
, 2);
2724 if (prev
->keyword
== KEYWORD_DEFAULT
||
2725 prev2
->keyword
== KEYWORD_CASE
||
2728 reinitStatement (st
, FALSE
);
2734 /* Skips over any initializing value which may follow an '=' character in a
2735 * variable definition.
2737 static int skipInitializer (statementInfo
*const st
)
2739 boolean done
= FALSE
;
2744 c
= skipToNonWhite ();
2747 longjmp (Exception
, (int) ExceptionFormattingError
);
2751 case ';': done
= TRUE
; break;
2754 if (st
->implementation
== IMP_VIRTUAL
)
2755 st
->implementation
= IMP_PURE_VIRTUAL
;
2758 case '[': skipToMatch ("[]"); break;
2759 case '(': skipToMatch ("()"); break;
2760 case '{': skipToMatch ("{}"); break;
2763 if (insideEnumBody (st
))
2765 else if (! isBraceFormat ())
2767 verbose ("%s: unexpected closing brace at line %lu\n",
2768 getInputFileName (), getInputLineNumber ());
2769 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
2779 static void processInitializer (statementInfo
*const st
)
2781 const boolean inEnumBody
= insideEnumBody (st
);
2782 const int c
= skipInitializer (st
);
2785 setToken (st
, TOKEN_SEMICOLON
);
2787 setToken (st
, TOKEN_COMMA
);
2788 else if (c
== '}' && inEnumBody
)
2791 setToken (st
, TOKEN_COMMA
);
2793 if (st
->scope
== SCOPE_EXTERN
)
2794 st
->scope
= SCOPE_GLOBAL
;
2797 static void parseIdentifier (statementInfo
*const st
, const int c
)
2799 tokenInfo
*const token
= activeToken (st
);
2801 readIdentifier (token
, c
);
2802 if (! isType (token
, TOKEN_NONE
))
2803 processToken (token
, st
);
2806 static void parseGeneralToken (statementInfo
*const st
, const int c
)
2808 const tokenInfo
*const prev
= prevToken (st
, 1);
2812 parseIdentifier (st
, c
);
2813 if (isType (st
->context
, TOKEN_NAME
) &&
2814 isType (activeToken (st
), TOKEN_NAME
) && isType (prev
, TOKEN_NAME
))
2816 initToken (st
->context
);
2819 else if (isExternCDecl (st
, c
))
2821 st
->declaration
= DECL_NOMANGLE
;
2822 st
->scope
= SCOPE_GLOBAL
;
2826 /* Reads characters from the pre-processor and assembles tokens, setting
2827 * the current statement state.
2829 static void nextToken (statementInfo
*const st
)
2832 tokenInfo
*token
= activeToken (st
);
2835 c
= skipToNonWhite();
2838 case EOF
: longjmp (Exception
, (int) ExceptionEOF
); break;
2839 case '(': analyzeParens (st
); token
= activeToken (st
); break;
2840 case '*': setToken (st
, TOKEN_STAR
); break;
2841 case ',': setToken (st
, TOKEN_COMMA
); break;
2842 case ':': processColon (st
); break;
2843 case ';': setToken (st
, TOKEN_SEMICOLON
); break;
2844 case '<': skipToMatch ("<>"); break;
2845 case '=': processInitializer (st
); break;
2847 /* Hack for Vala: [..] can be a function attribute.
2848 * Seems not to have bad side effects, but have to test it more. */
2849 if (!isLanguage (Lang_vala
))
2850 setToken (st
, TOKEN_ARRAY
);
2853 case '{': setToken (st
, TOKEN_BRACE_OPEN
); break;
2854 case '}': setToken (st
, TOKEN_BRACE_CLOSE
); break;
2855 default: parseGeneralToken (st
, c
); break;
2857 } while (isType (token
, TOKEN_NONE
));
2859 if (isType (token
, TOKEN_SEMICOLON
) && st
->parent
)
2860 st
->parent
->nSemicolons
++;
2862 /* We want to know about non-keyword variable types */
2863 if (TOKEN_NONE
== st
->firstToken
->type
)
2865 if ((TOKEN_NAME
== token
->type
) || isDataTypeKeyword(token
))
2866 copyToken(st
->firstToken
, token
);
2871 * Scanning support functions
2873 static unsigned int contextual_fake_count
= 0;
2874 static statementInfo
*CurrentStatement
= NULL
;
2876 static statementInfo
*newStatement (statementInfo
*const parent
)
2878 statementInfo
*const st
= xMalloc (1, statementInfo
);
2881 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
2882 st
->token
[i
] = newToken ();
2884 st
->context
= newToken ();
2885 st
->blockName
= newToken ();
2886 st
->parentClasses
= vStringNew ();
2887 st
->firstToken
= newToken();
2889 initStatement (st
, parent
);
2890 CurrentStatement
= st
;
2895 static void deleteStatement (void)
2897 statementInfo
*const st
= CurrentStatement
;
2898 statementInfo
*const parent
= st
->parent
;
2901 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
2903 deleteToken(st
->token
[i
]); st
->token
[i
] = NULL
;
2905 deleteToken(st
->blockName
); st
->blockName
= NULL
;
2906 deleteToken(st
->context
); st
->context
= NULL
;
2907 vStringDelete(st
->parentClasses
); st
->parentClasses
= NULL
;
2908 deleteToken(st
->firstToken
);
2910 CurrentStatement
= parent
;
2913 static void deleteAllStatements (void)
2915 while (CurrentStatement
!= NULL
)
2919 static boolean
isStatementEnd (const statementInfo
*const st
)
2921 const tokenInfo
*const token
= activeToken (st
);
2924 if (isType (token
, TOKEN_SEMICOLON
))
2926 else if (isType (token
, TOKEN_BRACE_CLOSE
))
2927 /* Java, D, C#, Vala do not require semicolons to end a block. Neither do
2928 * C++ namespaces. All other blocks require a semicolon to terminate them.
2930 isEnd
= (boolean
) (isLanguage (Lang_java
) || isLanguage (Lang_d
) ||
2931 isLanguage (Lang_csharp
) || isLanguage (Lang_vala
) ||
2932 ! isContextualStatement (st
));
2939 static void checkStatementEnd (statementInfo
*const st
)
2941 const tokenInfo
*const token
= activeToken (st
);
2942 boolean comma
= isType (token
, TOKEN_COMMA
);
2944 if (comma
|| isStatementEnd (st
))
2946 reinitStatementWithToken (st
, activeToken (st
), comma
);
2948 DebugStatement ( if (debug (DEBUG_PARSE
)) printf ("<ES>"); )
2953 cppBeginStatement ();
2958 static void nest (statementInfo
*const st
, const unsigned int nestLevel
)
2960 switch (st
->declaration
)
2964 case DECL_INTERFACE
:
2965 case DECL_NAMESPACE
:
2969 createTags (nestLevel
, st
);
2976 setToken (st
, TOKEN_BRACE_CLOSE
);
2979 static void tagCheck (statementInfo
*const st
)
2981 const tokenInfo
*const token
= activeToken (st
);
2982 const tokenInfo
*const prev
= prevToken (st
, 1);
2983 const tokenInfo
*const prev2
= prevToken (st
, 2);
2985 switch (token
->type
)
2989 if (insideEnumBody (st
) &&
2990 /* Java enumerations can contain members after a semicolon */
2991 (! isLanguage(Lang_java
) || st
->parent
->nSemicolons
< 1))
2992 qualifyEnumeratorTag (st
, token
);
2998 if (st
->haveQualifyingName
)
2999 makeTag (token
, st
, FALSE
, TAG_PACKAGE
);
3003 case TOKEN_BRACE_OPEN
:
3005 if (isType (prev
, TOKEN_ARGS
))
3007 if (st
->declaration
== DECL_FUNCTION_TEMPLATE
)
3008 qualifyFunctionTag (st
, st
->blockName
);
3009 else if (st
->haveQualifyingName
)
3011 if (isType (prev2
, TOKEN_NAME
))
3012 copyToken (st
->blockName
, prev2
);
3013 /* D structure templates */
3014 if (isLanguage (Lang_d
) &&
3015 (st
->declaration
== DECL_CLASS
|| st
->declaration
== DECL_STRUCT
||
3016 st
->declaration
== DECL_INTERFACE
|| st
->declaration
== DECL_NAMESPACE
))
3017 qualifyBlockTag (st
, prev2
);
3020 st
->declaration
= DECL_FUNCTION
;
3021 qualifyFunctionTag (st
, prev2
);
3025 else if (isContextualStatement (st
))
3027 tokenInfo
*name_token
= (tokenInfo
*)prev
;
3028 boolean free_name_token
= FALSE
;
3030 /* C++ 11 allows class <name> final { ... } */
3031 if (isLanguage (Lang_cpp
) && isType (prev
, TOKEN_NAME
) &&
3032 strcmp("final", vStringValue(prev
->name
)) == 0 &&
3033 isType(prev2
, TOKEN_NAME
))
3035 name_token
= (tokenInfo
*)prev2
;
3036 copyToken (st
->blockName
, name_token
);
3038 else if (isType (name_token
, TOKEN_NAME
))
3040 if (!isLanguage (Lang_vala
))
3041 copyToken (st
->blockName
, name_token
);
3044 switch (st
->declaration
)
3048 case DECL_INTERFACE
:
3049 case DECL_NAMESPACE
:
3051 copyToken (st
->blockName
, name_token
);
3054 /* anything else can be a property */
3056 /* makeTag (prev, st, FALSE, TAG_PROPERTY); */
3057 /* FIXME: temporary hack to get properties shown */
3058 makeTag (prev
, st
, FALSE
, TAG_FIELD
);
3063 else if (isLanguage (Lang_csharp
))
3064 makeTag (prev
, st
, FALSE
, TAG_PROPERTY
);
3067 tokenInfo
*contextual_token
= (tokenInfo
*)prev
;
3068 if(isContextualKeyword (contextual_token
))
3072 name_token
= newToken ();
3073 free_name_token
= TRUE
;
3074 copyToken (name_token
, contextual_token
);
3076 sprintf(buffer
, "anon_%s_%d", name_token
->name
->buffer
, contextual_fake_count
++);
3077 vStringClear(name_token
->name
);
3078 vStringCatS(name_token
->name
, buffer
);
3080 name_token
->type
= TOKEN_NAME
;
3081 name_token
->keyword
= KEYWORD_NONE
;
3084 contextual_token
= activeToken (st
);
3085 copyToken (contextual_token
, token
);
3086 copyToken ((tokenInfo
*const)token
, name_token
);
3087 copyToken (st
->blockName
, name_token
);
3088 copyToken (st
->firstToken
, name_token
);
3091 qualifyBlockTag (st
, name_token
);
3092 if (free_name_token
)
3093 deleteToken (name_token
);
3098 case TOKEN_SEMICOLON
:
3101 if (insideEnumBody (st
) &&
3102 /* Java enumerations can contain members after a semicolon */
3103 (! isLanguage (Lang_java
) || st
->parent
->nSemicolons
< 2))
3105 else if (isType (prev
, TOKEN_NAME
))
3107 if (isContextualKeyword (prev2
))
3108 makeTag (prev
, st
, TRUE
, TAG_EXTERN_VAR
);
3110 qualifyVariableTag (st
, prev
);
3112 else if (isType (prev
, TOKEN_ARGS
) && isType (prev2
, TOKEN_NAME
))
3114 qualifyFunctionDeclTag (st
, prev2
);
3123 /* Parses the current file and decides whether to write out and tags that
3126 static void createTags (const unsigned int nestLevel
,
3127 statementInfo
*const parent
)
3129 statementInfo
*const st
= newStatement (parent
);
3131 DebugStatement ( if (nestLevel
> 0) debugParseNest (TRUE
, nestLevel
); )
3138 token
= activeToken (st
);
3140 if (isType (token
, TOKEN_BRACE_CLOSE
))
3146 verbose ("%s: unexpected closing brace at line %lu\n",
3147 getInputFileName (), getInputLineNumber ());
3148 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
3151 else if (isType (token
, TOKEN_DOUBLE_COLON
))
3153 addContext (st
, prevToken (st
, 1));
3158 tagCheck (st
);/* this can add new token */
3159 if (isType (activeToken (st
), TOKEN_BRACE_OPEN
))
3160 nest (st
, nestLevel
+ 1);
3161 checkStatementEnd (st
);
3165 DebugStatement ( if (nestLevel
> 0) debugParseNest (FALSE
, nestLevel
- 1); )
3168 static boolean
findCTags (const unsigned int passCount
)
3170 exception_t exception
;
3173 contextual_fake_count
= 0;
3175 Assert (passCount
< 3);
3176 cppInit ((boolean
) (passCount
> 1), isLanguage (Lang_csharp
), isLanguage (Lang_cpp
));
3178 exception
= (exception_t
) setjmp (Exception
);
3181 if (exception
== ExceptionNone
)
3183 createTags (0, NULL
);
3187 deleteAllStatements ();
3188 if (exception
== ExceptionBraceFormattingError
&& passCount
== 1)
3191 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3192 getInputFileName ());
3199 static void buildKeywordHash (const langType language
, unsigned int idx
)
3201 const size_t count
= sizeof (KeywordTable
) / sizeof (KeywordTable
[0]);
3203 for (i
= 0 ; i
< count
; ++i
)
3205 const keywordDesc
* const p
= &KeywordTable
[i
];
3206 if (p
->isValid
[idx
])
3207 addKeyword (p
->name
, language
, (int) p
->id
);
3211 static void initializeCParser (const langType language
)
3214 buildKeywordHash (language
, 0);
3217 static void initializeCppParser (const langType language
)
3219 Lang_cpp
= language
;
3220 buildKeywordHash (language
, 1);
3223 static void initializeJavaParser (const langType language
)
3225 Lang_java
= language
;
3226 buildKeywordHash (language
, 3);
3229 static void initializeDParser (const langType language
)
3231 /* treat these like const - some are for parsing like const(Type), some are just
3232 * function attributes */
3233 const char *const_aliases
[] = {"immutable", "nothrow", "pure", "shared", NULL
};
3237 buildKeywordHash (language
, 6);
3239 for (s
= const_aliases
; *s
!= NULL
; s
++)
3241 addKeyword (*s
, language
, KEYWORD_CONST
);
3243 /* other keyword aliases */
3244 addKeyword ("alias", language
, KEYWORD_TYPEDEF
);
3245 /* skip 'static assert(...)' like 'static if (...)' */
3246 addKeyword ("assert", language
, KEYWORD_IF
);
3247 addKeyword ("unittest", language
, KEYWORD_BODY
); /* ignore */
3248 addKeyword ("version", language
, KEYWORD_NAMESPACE
); /* parse block */
3251 static void initializeGLSLParser (const langType language
)
3253 Lang_glsl
= language
;
3254 buildKeywordHash (language
, 0); /* C keywords */
3257 static void initializeFeriteParser (const langType language
)
3259 Lang_ferite
= language
;
3260 buildKeywordHash (language
, 1); /* C++ keywords */
3263 static void initializeCsharpParser (const langType language
)
3265 Lang_csharp
= language
;
3266 buildKeywordHash (language
, 2);
3269 static void initializeValaParser (const langType language
)
3271 Lang_vala
= language
;
3272 buildKeywordHash (language
, 5);
3274 /* keyword aliases */
3275 addKeyword ("ensures", language
, KEYWORD_ATTRIBUTE
); /* ignore */
3276 addKeyword ("errordomain", language
, KEYWORD_ENUM
); /* looks like enum */
3277 addKeyword ("requires", language
, KEYWORD_ATTRIBUTE
); /* ignore */
3280 extern parserDefinition
* CParser (void)
3282 static const char *const extensions
[] = { "c", "pc", "sc", NULL
};
3283 parserDefinition
* def
= parserNew ("C");
3284 def
->kinds
= CKinds
;
3285 def
->kindCount
= KIND_COUNT (CKinds
);
3286 def
->extensions
= extensions
;
3287 def
->parser2
= findCTags
;
3288 def
->initialize
= initializeCParser
;
3292 extern parserDefinition
* CppParser (void)
3294 static const char *const extensions
[] = {
3295 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3297 #ifndef CASE_INSENSITIVE_FILENAMES
3302 parserDefinition
* def
= parserNew ("C++");
3303 def
->kinds
= CKinds
;
3304 def
->kindCount
= KIND_COUNT (CKinds
);
3305 def
->extensions
= extensions
;
3306 def
->parser2
= findCTags
;
3307 def
->initialize
= initializeCppParser
;
3311 extern parserDefinition
* JavaParser (void)
3313 static const char *const extensions
[] = { "java", NULL
};
3314 parserDefinition
* def
= parserNew ("Java");
3315 def
->kinds
= JavaKinds
;
3316 def
->kindCount
= KIND_COUNT (JavaKinds
);
3317 def
->extensions
= extensions
;
3318 def
->parser2
= findCTags
;
3319 def
->initialize
= initializeJavaParser
;
3323 extern parserDefinition
* DParser (void)
3325 static const char *const extensions
[] = { "d", "di", NULL
};
3326 parserDefinition
* def
= parserNew ("D");
3327 def
->kinds
= DKinds
;
3328 def
->kindCount
= KIND_COUNT (DKinds
);
3329 def
->extensions
= extensions
;
3330 def
->parser2
= findCTags
;
3331 def
->initialize
= initializeDParser
;
3335 extern parserDefinition
* GLSLParser (void)
3337 static const char *const extensions
[] = { "glsl", "frag", "vert", NULL
};
3338 parserDefinition
* def
= parserNew ("GLSL");
3339 def
->kinds
= CKinds
;
3340 def
->kindCount
= KIND_COUNT (CKinds
);
3341 def
->extensions
= extensions
;
3342 def
->parser2
= findCTags
;
3343 def
->initialize
= initializeGLSLParser
;
3347 extern parserDefinition
* FeriteParser (void)
3349 static const char *const extensions
[] = { "fe", NULL
};
3350 parserDefinition
* def
= parserNew ("Ferite");
3351 def
->kinds
= CKinds
;
3352 def
->kindCount
= KIND_COUNT (CKinds
);
3353 def
->extensions
= extensions
;
3354 def
->parser2
= findCTags
;
3355 def
->initialize
= initializeFeriteParser
;
3359 extern parserDefinition
* CsharpParser (void)
3361 static const char *const extensions
[] = { "cs", NULL
};
3362 parserDefinition
* def
= parserNew ("C#");
3363 def
->kinds
= CsharpKinds
;
3364 def
->kindCount
= KIND_COUNT (CsharpKinds
);
3365 def
->extensions
= extensions
;
3366 def
->parser2
= findCTags
;
3367 def
->initialize
= initializeCsharpParser
;
3371 extern parserDefinition
* ValaParser (void)
3373 static const char *const extensions
[] = { "vala", NULL
};
3374 parserDefinition
* def
= parserNew ("Vala");
3375 def
->kinds
= ValaKinds
;
3376 def
->kindCount
= KIND_COUNT (ValaKinds
);
3377 def
->extensions
= extensions
;
3378 def
->parser2
= findCTags
;
3379 def
->initialize
= initializeValaParser
;
3382 /* vi:set tabstop=8 shiftwidth=4: */