3 * Copyright (c) 1996-2001, Darren Hiebert
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
8 * This module contains functions for parsing and scanning C, C++, D and Java
15 #include "general.h" /* must always come first */
32 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
33 #define parentDecl(st) ((st)->parent == NULL ? \
34 DECL_NONE : (st)->parent->declaration)
35 #define isType(token,t) (boolean) ((token)->type == (t))
36 #define insideEnumBody(st) (boolean) ((st)->parent == NULL ? FALSE : \
37 ((st)->parent->declaration == DECL_ENUM))
38 #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
39 ! (st)->haveQualifyingName && (st)->scope == SCOPE_EXTERN)
41 #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
47 enum { NumTokens
= 12 };
49 typedef enum eException
{
50 ExceptionNone
, ExceptionEOF
, ExceptionFormattingError
,
51 ExceptionBraceFormattingError
54 /* Used to specify type of keyword.
56 typedef enum eKeywordId
{
58 KEYWORD_ATTRIBUTE
, KEYWORD_ABSTRACT
,
59 KEYWORD_BOOLEAN
, KEYWORD_BYTE
, KEYWORD_BAD_STATE
, KEYWORD_BAD_TRANS
,
60 KEYWORD_BIND
, KEYWORD_BIND_VAR
, KEYWORD_BIT
,
61 KEYWORD_CASE
, KEYWORD_CATCH
, KEYWORD_CHAR
, KEYWORD_CLASS
, KEYWORD_CONST
,
62 KEYWORD_CONSTRAINT
, KEYWORD_COVERAGE_BLOCK
, KEYWORD_COVERAGE_DEF
,
63 KEYWORD_DEFAULT
, KEYWORD_DELEGATE
, KEYWORD_DELETE
, KEYWORD_DO
,
65 KEYWORD_ELSE
, KEYWORD_ENUM
, KEYWORD_EXPLICIT
, KEYWORD_EXTERN
,
66 KEYWORD_EXTENDS
, KEYWORD_EVENT
,
67 KEYWORD_FINAL
, KEYWORD_FLOAT
, KEYWORD_FOR
, KEYWORD_FRIEND
, KEYWORD_FUNCTION
,
69 KEYWORD_IF
, KEYWORD_IMPLEMENTS
, KEYWORD_IMPORT
, KEYWORD_INLINE
, KEYWORD_INT
,
70 KEYWORD_INOUT
, KEYWORD_INPUT
, KEYWORD_INTEGER
, KEYWORD_INTERFACE
,
72 KEYWORD_LOCAL
, KEYWORD_LONG
,
73 KEYWORD_M_BAD_STATE
, KEYWORD_M_BAD_TRANS
, KEYWORD_M_STATE
, KEYWORD_M_TRANS
,
74 KEYWORD_MODULE
, KEYWORD_MUTABLE
,
75 KEYWORD_NAMESPACE
, KEYWORD_NEW
, KEYWORD_NEWCOV
, KEYWORD_NATIVE
,
76 KEYWORD_OPERATOR
, KEYWORD_OUTPUT
, KEYWORD_OVERLOAD
, KEYWORD_OVERRIDE
,
77 KEYWORD_PACKED
, KEYWORD_PORT
, KEYWORD_PACKAGE
, KEYWORD_PRIVATE
,
78 KEYWORD_PROGRAM
, KEYWORD_PROTECTED
, KEYWORD_PUBLIC
,
79 KEYWORD_REGISTER
, KEYWORD_RETURN
,
80 KEYWORD_SHADOW
, KEYWORD_STATE
,
81 KEYWORD_SHORT
, KEYWORD_SIGNED
, KEYWORD_SIZE_T
, KEYWORD_STATIC
, KEYWORD_STRING
,
82 KEYWORD_STRUCT
, KEYWORD_SWITCH
, KEYWORD_SYNCHRONIZED
,
83 KEYWORD_TASK
, KEYWORD_TEMPLATE
, KEYWORD_THIS
, KEYWORD_THROW
,
84 KEYWORD_THROWS
, KEYWORD_TRANSIENT
, KEYWORD_TRANS
, KEYWORD_TRANSITION
,
85 KEYWORD_TRY
, KEYWORD_TYPEDEF
, KEYWORD_TYPENAME
,
86 KEYWORD_UINT
, KEYWORD_ULONG
, KEYWORD_UNION
, KEYWORD_UNSIGNED
, KEYWORD_USHORT
,
88 KEYWORD_VIRTUAL
, KEYWORD_VOID
, KEYWORD_VOLATILE
,
89 KEYWORD_WCHAR_T
, KEYWORD_WHILE
92 /* Used to determine whether keyword is valid for the current language and
95 typedef struct sKeywordDesc
{
98 short isValid
[5]; /* indicates languages for which kw is valid */
101 /* Used for reporting the type of object parsed by nextToken ().
103 typedef enum eTokenType
{
104 TOKEN_NONE
, /* none */
105 TOKEN_ARGS
, /* a parenthetical pair and its contents */
108 TOKEN_COMMA
, /* the comma character */
109 TOKEN_DOUBLE_COLON
, /* double colon indicates nested-name-specifier */
111 TOKEN_NAME
, /* an unknown name */
112 TOKEN_PACKAGE
, /* a Java package name */
113 TOKEN_PAREN_NAME
, /* a single name in parentheses */
114 TOKEN_SEMICOLON
, /* the semicolon character */
115 TOKEN_SPEC
, /* a storage class specifier, qualifier, type, etc. */
116 TOKEN_STAR
, /* pointer detection */
117 TOKEN_ARRAY
, /* array detection */
121 /* This describes the scoping of the current statement.
123 typedef enum eTagScope
{
124 SCOPE_GLOBAL
, /* no storage class specified */
125 SCOPE_STATIC
, /* static storage class */
126 SCOPE_EXTERN
, /* external storage class */
127 SCOPE_FRIEND
, /* declares access only */
128 SCOPE_TYPEDEF
, /* scoping depends upon context */
132 typedef enum eDeclaration
{
134 DECL_BASE
, /* base type (default) */
139 DECL_IGNORE
, /* non-taggable "declaration" */
143 DECL_NOMANGLE
, /* C++ name demangling block */
150 typedef enum eVisibilityType
{
155 ACCESS_DEFAULT
, /* Java-specific */
159 /* Information about the parent class of a member (if any).
161 typedef struct sMemberInfo
{
162 accessType access
; /* access of current statement */
163 accessType accessDefault
; /* access default for current statement */
166 typedef struct sTokenInfo
{
169 vString
* name
; /* the name of the token */
170 unsigned long lineNumber
; /* line number of tag */
171 fpos_t filePosition
; /* file position of line containing name */
174 typedef enum eImplementation
{
182 /* Describes the statement currently undergoing analysis.
184 typedef struct sStatementInfo
{
186 declType declaration
; /* specifier associated with TOKEN_SPEC */
187 boolean gotName
; /* was a name parsed yet? */
188 boolean haveQualifyingName
; /* do we have a name we are considering? */
189 boolean gotParenName
; /* was a name inside parentheses parsed yet? */
190 boolean gotArgs
; /* was a list of parameters parsed yet? */
191 impType implementation
; /* abstract or concrete implementation? */
192 unsigned int tokenIndex
; /* currently active token */
193 tokenInfo
* token
[((int) NumTokens
)];
194 tokenInfo
* context
; /* accumulated scope of current statement */
195 tokenInfo
* blockName
; /* name of current block */
196 memberInfo member
; /* information regarding parent class/struct */
197 vString
* parentClasses
; /* parent classes */
198 struct sStatementInfo
*parent
; /* statement we are nested within */
199 long argEndPosition
; /* Position where argument list ended */
200 tokenInfo
* firstToken
; /* First token in the statement */
203 /* Describes the type of tag being generated.
205 typedef enum eTagType
{
207 TAG_CLASS
, /* class name */
208 TAG_ENUM
, /* enumeration name */
209 TAG_ENUMERATOR
, /* enumerator (enumeration value) */
210 TAG_FIELD
, /* field (Java) */
211 TAG_FUNCTION
, /* function definition */
212 TAG_INTERFACE
, /* interface declaration */
213 TAG_MEMBER
, /* structure, class or interface member */
214 TAG_METHOD
, /* method declaration */
215 TAG_NAMESPACE
, /* namespace name */
216 TAG_PACKAGE
, /* package name */
217 TAG_PROTOTYPE
, /* function prototype or declaration */
218 TAG_STRUCT
, /* structure name */
219 TAG_TYPEDEF
, /* typedef name */
220 TAG_UNION
, /* union name */
221 TAG_VARIABLE
, /* variable definition */
222 TAG_EXTERN_VAR
, /* external variable declaration */
223 TAG_MACRO
, /* #define s */
224 TAG_EVENT
, /* event */
225 TAG_LOCAL
, /* local variable definition */
226 TAG_PROPERTY
, /* property name */
227 TAG_COUNT
/* must be last */
230 typedef struct sParenInfo
{
232 boolean isKnrParamList
;
233 boolean isNameCandidate
;
234 boolean invalidContents
;
236 unsigned int parameterCount
;
243 static jmp_buf Exception
;
245 static langType Lang_c
;
246 static langType Lang_cpp
;
247 static langType Lang_csharp
;
248 static langType Lang_java
;
249 static langType Lang_d
;
250 static langType Lang_glsl
;
251 static langType Lang_ferite
;
253 /* Used to index into the CKinds table. */
256 CK_CLASS
, CK_DEFINE
, CK_ENUMERATOR
, CK_FUNCTION
,
257 CK_ENUMERATION
, CK_MEMBER
, CK_NAMESPACE
, CK_PROTOTYPE
,
258 CK_STRUCT
, CK_TYPEDEF
, CK_UNION
, CK_VARIABLE
,
262 static kindOption CKinds
[] = {
263 { TRUE
, 'c', "class", "classes"},
264 { TRUE
, 'd', "macro", "macro definitions"},
265 { TRUE
, 'e', "enumerator", "enumerators (values inside an enumeration)"},
266 { TRUE
, 'f', "function", "function definitions"},
267 { TRUE
, 'g', "enum", "enumeration names"},
268 { TRUE
, 'm', "member", "class, struct, and union members"},
269 { TRUE
, 'n', "namespace", "namespaces"},
270 { FALSE
, 'p', "prototype", "function prototypes"},
271 { TRUE
, 's', "struct", "structure names"},
272 { TRUE
, 't', "typedef", "typedefs"},
273 { TRUE
, 'u', "union", "union names"},
274 { TRUE
, 'v', "variable", "variable definitions"},
275 { FALSE
, 'x', "externvar", "external variable declarations"},
278 /* Used to index into the JavaKinds table. */
281 JK_CLASS
, JK_FIELD
, JK_INTERFACE
, JK_METHOD
,
282 JK_PACKAGE
, JK_ACCESS
, JK_CLASS_PREFIX
285 static kindOption JavaKinds
[] = {
286 { TRUE
, 'c', "class", "classes"},
287 { TRUE
, 'f', "field", "fields"},
288 { TRUE
, 'i', "interface", "interfaces"},
289 { TRUE
, 'm', "method", "methods"},
290 { TRUE
, 'p', "package", "packages"},
295 CSK_CLASS
, CSK_DEFINE
, CSK_ENUMERATOR
, CSK_EVENT
, CSK_FIELD
,
296 CSK_ENUMERATION
, CSK_INTERFACE
, CSK_LOCAL
, CSK_METHOD
,
297 CSK_NAMESPACE
, CSK_PROPERTY
, CSK_STRUCT
, CSK_TYPEDEF
300 static kindOption CsharpKinds
[] = {
301 { TRUE
, 'c', "class", "classes"},
302 { TRUE
, 'd', "macro", "macro definitions"},
303 { TRUE
, 'e', "enumerator", "enumerators (values inside an enumeration)"},
304 { TRUE
, 'E', "event", "events"},
305 { TRUE
, 'f', "field", "fields"},
306 { TRUE
, 'g', "enum", "enumeration names"},
307 { TRUE
, 'i', "interface", "interfaces"},
308 { FALSE
, 'l', "local", "local variables"},
309 { TRUE
, 'm', "method", "methods"},
310 { TRUE
, 'n', "namespace", "namespaces"},
311 { TRUE
, 'p', "property", "properties"},
312 { TRUE
, 's', "struct", "structure names"},
313 { TRUE
, 't', "typedef", "typedefs"},
316 static const keywordDesc KeywordTable
[] = {
318 /* ANSI C | C# Java */
320 /* keyword keyword ID | | | | | */
321 { "__attribute__", KEYWORD_ATTRIBUTE
, { 1, 1, 1, 0, 0 } },
322 { "abstract", KEYWORD_ABSTRACT
, { 0, 0, 1, 1, 0 } },
323 { "bad_state", KEYWORD_BAD_STATE
, { 0, 0, 0, 0, 1 } },
324 { "bad_trans", KEYWORD_BAD_TRANS
, { 0, 0, 0, 0, 1 } },
325 { "bind", KEYWORD_BIND
, { 0, 0, 0, 0, 1 } },
326 { "bind_var", KEYWORD_BIND_VAR
, { 0, 0, 0, 0, 1 } },
327 { "bit", KEYWORD_BIT
, { 0, 0, 0, 0, 1 } },
328 { "boolean", KEYWORD_BOOLEAN
, { 0, 0, 0, 1, 0 } },
329 { "byte", KEYWORD_BYTE
, { 0, 0, 0, 1, 0 } },
330 { "case", KEYWORD_CASE
, { 1, 1, 1, 1, 0 } },
331 { "catch", KEYWORD_CATCH
, { 0, 1, 1, 0, 0 } },
332 { "char", KEYWORD_CHAR
, { 1, 1, 1, 1, 0 } },
333 { "class", KEYWORD_CLASS
, { 0, 1, 1, 1, 1 } },
334 { "const", KEYWORD_CONST
, { 1, 1, 1, 1, 0 } },
335 { "constraint", KEYWORD_CONSTRAINT
, { 0, 0, 0, 0, 1 } },
336 { "coverage_block", KEYWORD_COVERAGE_BLOCK
, { 0, 0, 0, 0, 1 } },
337 { "coverage_def", KEYWORD_COVERAGE_DEF
, { 0, 0, 0, 0, 1 } },
338 { "do", KEYWORD_DO
, { 1, 1, 1, 1, 0 } },
339 { "default", KEYWORD_DEFAULT
, { 1, 1, 1, 1, 0 } },
340 { "delegate", KEYWORD_DELEGATE
, { 0, 0, 1, 0, 0 } },
341 { "delete", KEYWORD_DELETE
, { 0, 1, 0, 0, 0 } },
342 { "double", KEYWORD_DOUBLE
, { 1, 1, 1, 1, 0 } },
343 { "else", KEYWORD_ELSE
, { 1, 1, 0, 1, 0 } },
344 { "enum", KEYWORD_ENUM
, { 1, 1, 1, 1, 1 } },
345 { "event", KEYWORD_EVENT
, { 0, 0, 1, 0, 1 } },
346 { "explicit", KEYWORD_EXPLICIT
, { 0, 1, 1, 0, 0 } },
347 { "extends", KEYWORD_EXTENDS
, { 0, 0, 0, 1, 1 } },
348 { "extern", KEYWORD_EXTERN
, { 1, 1, 1, 0, 1 } },
349 { "final", KEYWORD_FINAL
, { 0, 0, 0, 1, 0 } },
350 { "float", KEYWORD_FLOAT
, { 1, 1, 1, 1, 0 } },
351 { "for", KEYWORD_FOR
, { 1, 1, 1, 1, 0 } },
352 { "friend", KEYWORD_FRIEND
, { 0, 1, 0, 0, 0 } },
353 { "function", KEYWORD_FUNCTION
, { 0, 0, 0, 0, 1 } },
354 { "goto", KEYWORD_GOTO
, { 1, 1, 1, 1, 0 } },
355 { "if", KEYWORD_IF
, { 1, 1, 1, 1, 0 } },
356 { "implements", KEYWORD_IMPLEMENTS
, { 0, 0, 0, 1, 0 } },
357 { "import", KEYWORD_IMPORT
, { 0, 1, 0, 1, 0 } }, /* D */
358 { "inline", KEYWORD_INLINE
, { 0, 1, 0, 0, 0 } },
359 { "inout", KEYWORD_INOUT
, { 0, 0, 0, 0, 1 } },
360 { "input", KEYWORD_INPUT
, { 0, 0, 0, 0, 1 } },
361 { "int", KEYWORD_INT
, { 1, 1, 1, 1, 0 } },
362 { "integer", KEYWORD_INTEGER
, { 0, 0, 0, 0, 1 } },
363 { "interface", KEYWORD_INTERFACE
, { 0, 0, 1, 1, 1 } },
364 { "internal", KEYWORD_INTERNAL
, { 0, 0, 1, 0, 0 } },
365 { "local", KEYWORD_LOCAL
, { 0, 0, 0, 0, 1 } },
366 { "long", KEYWORD_LONG
, { 1, 1, 1, 1, 0 } },
367 { "m_bad_state", KEYWORD_M_BAD_STATE
, { 0, 0, 0, 0, 1 } },
368 { "m_bad_trans", KEYWORD_M_BAD_TRANS
, { 0, 0, 0, 0, 1 } },
369 { "m_state", KEYWORD_M_STATE
, { 0, 0, 0, 0, 1 } },
370 { "m_trans", KEYWORD_M_TRANS
, { 0, 0, 0, 0, 1 } },
371 { "mutable", KEYWORD_MUTABLE
, { 0, 1, 0, 0, 0 } },
372 { "module", KEYWORD_MODULE
, { 0, 1, 0, 0, 0 } }, /* D */
373 { "namespace", KEYWORD_NAMESPACE
, { 0, 1, 1, 0, 0 } },
374 { "native", KEYWORD_NATIVE
, { 0, 0, 0, 1, 0 } },
375 { "new", KEYWORD_NEW
, { 0, 1, 1, 1, 0 } },
376 { "newcov", KEYWORD_NEWCOV
, { 0, 0, 0, 0, 1 } },
377 { "operator", KEYWORD_OPERATOR
, { 0, 1, 1, 0, 0 } },
378 { "output", KEYWORD_OUTPUT
, { 0, 0, 0, 0, 1 } },
379 { "overload", KEYWORD_OVERLOAD
, { 0, 1, 0, 0, 0 } },
380 { "override", KEYWORD_OVERRIDE
, { 0, 0, 1, 0, 0 } },
381 { "package", KEYWORD_PACKAGE
, { 0, 0, 0, 1, 0 } },
382 { "packed", KEYWORD_PACKED
, { 0, 0, 0, 0, 1 } },
383 { "port", KEYWORD_PORT
, { 0, 0, 0, 0, 1 } },
384 { "private", KEYWORD_PRIVATE
, { 0, 1, 1, 1, 0 } },
385 { "program", KEYWORD_PROGRAM
, { 0, 0, 0, 0, 1 } },
386 { "protected", KEYWORD_PROTECTED
, { 0, 1, 1, 1, 1 } },
387 { "public", KEYWORD_PUBLIC
, { 0, 1, 1, 1, 1 } },
388 { "register", KEYWORD_REGISTER
, { 1, 1, 0, 0, 0 } },
389 { "return", KEYWORD_RETURN
, { 1, 1, 1, 1, 0 } },
390 { "shadow", KEYWORD_SHADOW
, { 0, 0, 0, 0, 1 } },
391 { "short", KEYWORD_SHORT
, { 1, 1, 1, 1, 0 } },
392 { "signed", KEYWORD_SIGNED
, { 1, 1, 0, 0, 0 } },
393 { "size_t", KEYWORD_SIZE_T
, { 1, 1, 0, 0, 0 } },
394 { "state", KEYWORD_STATE
, { 0, 0, 0, 0, 1 } },
395 { "static", KEYWORD_STATIC
, { 1, 1, 1, 1, 1 } },
396 { "string", KEYWORD_STRING
, { 0, 0, 1, 0, 1 } },
397 { "struct", KEYWORD_STRUCT
, { 1, 1, 1, 0, 0 } },
398 { "switch", KEYWORD_SWITCH
, { 1, 1, 1, 1, 0 } },
399 { "synchronized", KEYWORD_SYNCHRONIZED
, { 0, 0, 0, 1, 0 } },
400 { "task", KEYWORD_TASK
, { 0, 0, 0, 0, 1 } },
401 { "template", KEYWORD_TEMPLATE
, { 0, 1, 0, 0, 0 } },
402 { "this", KEYWORD_THIS
, { 0, 0, 1, 1, 0 } }, /* allow D ctor tags */
403 { "throw", KEYWORD_THROW
, { 0, 1, 1, 1, 0 } },
404 { "throws", KEYWORD_THROWS
, { 0, 0, 0, 1, 0 } },
405 { "trans", KEYWORD_TRANS
, { 0, 0, 0, 0, 1 } },
406 { "transition", KEYWORD_TRANSITION
, { 0, 0, 0, 0, 1 } },
407 { "transient", KEYWORD_TRANSIENT
, { 0, 0, 0, 1, 0 } },
408 { "try", KEYWORD_TRY
, { 0, 1, 1, 0, 0 } },
409 { "typedef", KEYWORD_TYPEDEF
, { 1, 1, 1, 0, 1 } },
410 { "typename", KEYWORD_TYPENAME
, { 0, 1, 0, 0, 0 } },
411 { "uint", KEYWORD_UINT
, { 0, 0, 1, 0, 0 } },
412 { "ulong", KEYWORD_ULONG
, { 0, 0, 1, 0, 0 } },
413 { "union", KEYWORD_UNION
, { 1, 1, 0, 0, 0 } },
414 { "unsigned", KEYWORD_UNSIGNED
, { 1, 1, 1, 0, 0 } },
415 { "ushort", KEYWORD_USHORT
, { 0, 0, 1, 0, 0 } },
416 { "using", KEYWORD_USING
, { 0, 1, 1, 0, 0 } },
417 { "virtual", KEYWORD_VIRTUAL
, { 0, 1, 1, 0, 1 } },
418 { "void", KEYWORD_VOID
, { 1, 1, 1, 1, 1 } },
419 { "volatile", KEYWORD_VOLATILE
, { 1, 1, 1, 1, 0 } },
420 { "wchar_t", KEYWORD_WCHAR_T
, { 1, 1, 1, 0, 0 } },
421 { "while", KEYWORD_WHILE
, { 1, 1, 1, 1, 0 } }
426 * FUNCTION PROTOTYPES
428 static void createTags (const unsigned int nestLevel
, statementInfo
*const parent
);
429 static void copyToken (tokenInfo
*const dest
, const tokenInfo
*const src
);
430 static const char *getVarType (const statementInfo
*const st
);
433 * FUNCTION DEFINITIONS
436 /* Debugging functions added by Biswa */
437 #if defined(DEBUG_C) && DEBUG_C
438 static char *tokenTypeName
[] = {
439 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
440 "package", "paren-name", "';'", "spec", "*", "[]", "count"
443 static char *tagScopeNames
[] = {
444 "global", "static", "extern", "friend", "typedef", "count"};
446 static char *declTypeNames
[] = {
447 "none", "base", "class", "enum", "function", "ignore", "interface",
448 "namespace", "nomangle", "package", "struct", "union", "count"};
450 static char *impTypeNames
[] = {
451 "default", "abstract", "virtual", "pure-virtual", "count"};
453 void printToken(const tokenInfo
*const token
)
455 fprintf(stderr
, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName
[token
->type
],
456 token
->keyword
, vStringValue(token
->name
));
459 void printTagEntry(const tagEntryInfo
*tag
)
461 fprintf(stderr
, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag
->name
,
462 tag
->kindName
, tag
->extensionFields
.implementation
, tag
->extensionFields
.scope
[1],
463 tag
->extensionFields
.varType
);
466 void printStatement(const statementInfo
*const statement
)
469 statementInfo
*st
= (statementInfo
*) statement
;
472 fprintf(stderr
, "Statement Info:\n------------------------\n");
473 fprintf(stderr
, "scope: %s, decl: %s, impl: %s\n", tagScopeNames
[st
->scope
]
474 , declTypeNames
[st
->declaration
], impTypeNames
[st
->implementation
]);
475 for (i
=0; i
< NumTokens
; ++i
)
477 fprintf(stderr
, "Token %d %s: ", i
, (i
== st
->tokenIndex
)?"(current)":"");
478 printToken(st
->token
[i
]);
480 fprintf(stderr
, "Context: ");
481 printToken(st
->context
);
482 fprintf(stderr
, "Block: ");
483 printToken(st
->blockName
);
484 fprintf(stderr
, "Parent classes: %s\n", vStringValue(st
->parentClasses
));
485 fprintf(stderr
, "First token: ");
486 printToken(st
->firstToken
);
487 if (NULL
!= st
->parent
)
488 fprintf(stderr
, "Printing Parent:\n");
491 fprintf(stderr
, "-----------------------------------------------\n");
495 extern boolean
includingDefineTags (void)
497 return CKinds
[CK_DEFINE
].enabled
;
504 static void initToken (tokenInfo
* const token
)
506 token
->type
= TOKEN_NONE
;
507 token
->keyword
= KEYWORD_NONE
;
508 token
->lineNumber
= getSourceLineNumber ();
509 token
->filePosition
= getInputFilePosition ();
510 vStringClear (token
->name
);
513 static void advanceToken (statementInfo
* const st
)
515 if (st
->tokenIndex
>= (unsigned int) NumTokens
- 1)
523 initToken (st
->token
[st
->tokenIndex
]);
526 static tokenInfo
*prevToken (const statementInfo
*const st
, unsigned int n
)
528 unsigned int tokenIndex
;
529 unsigned int num
= (unsigned int) NumTokens
;
531 tokenIndex
= (st
->tokenIndex
+ num
- n
) % num
;
533 return st
->token
[tokenIndex
];
536 static void setToken (statementInfo
*const st
, const tokenType type
)
539 token
= activeToken (st
);
544 static void retardToken (statementInfo
*const st
)
546 if (st
->tokenIndex
== 0)
548 st
->tokenIndex
= (unsigned int) NumTokens
- 1;
554 setToken (st
, TOKEN_NONE
);
557 static tokenInfo
*newToken (void)
559 tokenInfo
*const token
= xMalloc (1, tokenInfo
);
560 token
->name
= vStringNew ();
565 static void deleteToken (tokenInfo
*const token
)
569 vStringDelete (token
->name
);
574 static const char *accessString (const accessType laccess
)
576 static const char *const names
[] ={
577 "?", "private", "protected", "public", "default"
579 Assert (sizeof (names
) / sizeof (names
[0]) == ACCESS_COUNT
);
580 Assert ((int) laccess
< ACCESS_COUNT
);
581 return names
[(int) laccess
];
584 static const char *implementationString (const impType imp
)
586 static const char *const names
[] ={
587 "?", "abstract", "virtual", "pure virtual"
589 Assert (sizeof (names
) / sizeof (names
[0]) == IMP_COUNT
);
590 Assert ((int) imp
< IMP_COUNT
);
591 return names
[(int) imp
];
595 * Debugging functions
600 #define boolString(c) ((c) ? "TRUE" : "FALSE")
602 static const char *tokenString (const tokenType type
)
604 static const char *const names
[] = {
605 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
606 "package", "paren-name", "semicolon", "specifier", "*", "[]", "count"
608 Assert (sizeof (names
) / sizeof (names
[0]) == TOKEN_COUNT
);
609 Assert ((int) type
< TOKEN_COUNT
);
610 return names
[(int) type
];
613 static const char *scopeString (const tagScope scope
)
615 static const char *const names
[] = {
616 "global", "static", "extern", "friend", "typedef"
618 Assert (sizeof (names
) / sizeof (names
[0]) == SCOPE_COUNT
);
619 Assert ((int) scope
< SCOPE_COUNT
);
620 return names
[(int) scope
];
623 static const char *declString (const declType declaration
)
625 static const char *const names
[] = {
626 "?", "base", "class", "enum", "function", "ignore", "interface",
627 "namespace", "no mangle", "package", "struct", "union",
629 Assert (sizeof (names
) / sizeof (names
[0]) == DECL_COUNT
);
630 Assert ((int) declaration
< DECL_COUNT
);
631 return names
[(int) declaration
];
634 static const char *keywordString (const keywordId keyword
)
636 const size_t count
= sizeof (KeywordTable
) / sizeof (KeywordTable
[0]);
637 const char *name
= "none";
639 for (i
= 0 ; i
< count
; ++i
)
641 const keywordDesc
*p
= &KeywordTable
[i
];
643 if (p
->id
== keyword
)
652 static void __unused__
pt (tokenInfo
*const token
)
654 if (isType (token
, TOKEN_NAME
))
655 printf ("type: %-12s: %-13s line: %lu\n",
656 tokenString (token
->type
), vStringValue (token
->name
),
658 else if (isType (token
, TOKEN_KEYWORD
))
659 printf ("type: %-12s: %-13s line: %lu\n",
660 tokenString (token
->type
), keywordString (token
->keyword
),
663 printf ("type: %-12s line: %lu\n",
664 tokenString (token
->type
), token
->lineNumber
);
667 static void __unused__
ps (statementInfo
*const st
)
670 printf ("scope: %s decl: %s gotName: %s gotParenName: %s\n",
671 scopeString (st
->scope
), declString (st
->declaration
),
672 boolString (st
->gotName
), boolString (st
->gotParenName
));
673 printf ("haveQualifyingName: %s\n", boolString (st
->haveQualifyingName
));
674 printf ("access: %s default: %s\n", accessString (st
->member
.access
),
675 accessString (st
->member
.accessDefault
));
677 pt (activeToken (st
));
678 for (i
= 1 ; i
< (unsigned int) NumTokens
; ++i
)
680 printf ("prev %u : ", i
);
681 pt (prevToken (st
, i
));
683 printf ("context: ");
690 * Statement management
693 static boolean
isDataTypeKeyword (const tokenInfo
*const token
)
695 switch (token
->keyword
)
697 case KEYWORD_BOOLEAN
:
706 case KEYWORD_WCHAR_T
:
709 default: return FALSE
;
714 static boolean
isVariableKeyword (const tokenInfo
*const token
)
716 switch (token
->keyword
)
720 case KEYWORD_REGISTER
:
722 case KEYWORD_VIRTUAL
:
724 case KEYWORD_UNSIGNED
:
726 default: return FALSE
;
731 static boolean
isContextualKeyword (const tokenInfo
*const token
)
734 switch (token
->keyword
)
738 case KEYWORD_INTERFACE
:
739 case KEYWORD_NAMESPACE
:
745 default: result
= FALSE
; break;
750 static boolean
isContextualStatement (const statementInfo
*const st
)
752 boolean result
= FALSE
;
753 if (st
!= NULL
) switch (st
->declaration
)
764 default: result
= FALSE
; break;
769 static boolean
isMember (const statementInfo
*const st
)
772 if (isType (st
->context
, TOKEN_NAME
))
775 result
= isContextualStatement (st
->parent
);
779 static void initMemberInfo (statementInfo
*const st
)
781 accessType accessDefault
= ACCESS_UNDEFINED
;
783 if (st
->parent
!= NULL
) switch (st
->parent
->declaration
)
787 accessDefault
= ACCESS_UNDEFINED
;
791 if (isLanguage (Lang_java
))
792 accessDefault
= ACCESS_DEFAULT
;
794 accessDefault
= ACCESS_PRIVATE
;
800 accessDefault
= ACCESS_PUBLIC
;
805 st
->member
.accessDefault
= accessDefault
;
806 st
->member
.access
= accessDefault
;
809 static void reinitStatement (statementInfo
*const st
, const boolean partial
)
815 st
->scope
= SCOPE_GLOBAL
;
816 if (isContextualStatement (st
->parent
))
817 st
->declaration
= DECL_BASE
;
819 st
->declaration
= DECL_NONE
;
821 st
->gotParenName
= FALSE
;
822 st
->implementation
= IMP_DEFAULT
;
825 st
->haveQualifyingName
= FALSE
;
826 st
->argEndPosition
= 0;
829 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
831 initToken (st
->token
[i
]);
834 initToken (st
->context
);
835 initToken (st
->blockName
);
836 vStringClear (st
->parentClasses
);
841 st
->member
.access
= st
->member
.accessDefault
;
843 /* Init first token */
845 initToken(st
->firstToken
);
848 static void reinitStatementWithToken (statementInfo
*const st
,
849 tokenInfo
*token
, const boolean partial
)
851 tokenInfo
*const save
= newToken ();
852 /* given token can be part of reinit statementInfo */
853 copyToken (save
, token
);
854 reinitStatement (st
, partial
);
855 token
= activeToken (st
);
856 copyToken (token
, save
);
858 ++st
->tokenIndex
; /* this is quite save becouse current tokenIndex = 0 */
861 static void initStatement (statementInfo
*const st
, statementInfo
*const parent
)
865 reinitStatement (st
, FALSE
);
868 const tokenInfo
*const src
= activeToken (parent
);
869 tokenInfo
*const dst
= activeToken (st
);
870 copyToken (dst
, src
);
876 * Tag generation functions
878 static cKind
cTagKind (const tagType type
)
880 cKind result
= CK_UNDEFINED
;
883 case TAG_CLASS
: result
= CK_CLASS
; break;
884 case TAG_ENUM
: result
= CK_ENUMERATION
; break;
885 case TAG_ENUMERATOR
: result
= CK_ENUMERATOR
; break;
886 case TAG_FUNCTION
: result
= CK_FUNCTION
; break;
887 case TAG_MEMBER
: result
= CK_MEMBER
; break;
888 case TAG_NAMESPACE
: result
= CK_NAMESPACE
; break;
889 case TAG_PROTOTYPE
: result
= CK_PROTOTYPE
; break;
890 case TAG_STRUCT
: result
= CK_STRUCT
; break;
891 case TAG_TYPEDEF
: result
= CK_TYPEDEF
; break;
892 case TAG_UNION
: result
= CK_UNION
; break;
893 case TAG_VARIABLE
: result
= CK_VARIABLE
; break;
894 case TAG_EXTERN_VAR
: result
= CK_EXTERN_VARIABLE
; break;
896 default: Assert ("Bad C tag type" == NULL
); break;
901 static csharpKind
csharpTagKind (const tagType type
)
903 csharpKind result
= CSK_UNDEFINED
;
906 case TAG_CLASS
: result
= CSK_CLASS
; break;
907 case TAG_ENUM
: result
= CSK_ENUMERATION
; break;
908 case TAG_ENUMERATOR
: result
= CSK_ENUMERATOR
; break;
909 case TAG_EVENT
: result
= CSK_EVENT
; break;
910 case TAG_FIELD
: result
= CSK_FIELD
; break;
911 case TAG_INTERFACE
: result
= CSK_INTERFACE
; break;
912 case TAG_LOCAL
: result
= CSK_LOCAL
; break;
913 case TAG_METHOD
: result
= CSK_METHOD
; break;
914 case TAG_NAMESPACE
: result
= CSK_NAMESPACE
; break;
915 case TAG_PROPERTY
: result
= CSK_PROPERTY
; break;
916 case TAG_STRUCT
: result
= CSK_STRUCT
; break;
917 case TAG_TYPEDEF
: result
= CSK_TYPEDEF
; break;
919 default: Assert ("Bad C# tag type" == NULL
); break;
924 static javaKind
javaTagKind (const tagType type
)
926 javaKind result
= JK_UNDEFINED
;
929 case TAG_CLASS
: result
= JK_CLASS
; break;
930 case TAG_FIELD
: result
= JK_FIELD
; break;
931 case TAG_INTERFACE
: result
= JK_INTERFACE
; break;
932 case TAG_METHOD
: result
= JK_METHOD
; break;
933 case TAG_PACKAGE
: result
= JK_PACKAGE
; break;
935 default: Assert ("Bad Java tag type" == NULL
); break;
940 static const char *tagName (const tagType type
)
943 if (isLanguage (Lang_java
))
944 result
= JavaKinds
[javaTagKind (type
)].name
;
945 else if (isLanguage (Lang_csharp
))
946 result
= CsharpKinds
[csharpTagKind (type
)].name
;
948 result
= CKinds
[cTagKind (type
)].name
;
952 static int tagLetter (const tagType type
)
955 if (isLanguage (Lang_java
))
956 result
= JavaKinds
[javaTagKind (type
)].letter
;
957 if (isLanguage (Lang_csharp
))
958 result
= CsharpKinds
[csharpTagKind (type
)].letter
;
960 result
= CKinds
[cTagKind (type
)].letter
;
965 static boolean includeTag (const tagType type, const boolean isFileScope)
968 if (isFileScope && ! Option.include.fileScope)
970 else if (isLanguage (Lang_java))
971 result = JavaKinds [javaTagKind (type)].enabled;
973 result = CKinds [cTagKind (type)].enabled;
978 static tagType
declToTagType (const declType declaration
)
980 tagType type
= TAG_UNDEFINED
;
984 case DECL_CLASS
: type
= TAG_CLASS
; break;
985 case DECL_ENUM
: type
= TAG_ENUM
; break;
986 case DECL_FUNCTION
: type
= TAG_FUNCTION
; break;
987 case DECL_INTERFACE
:type
= TAG_INTERFACE
; break;
988 case DECL_NAMESPACE
:type
= TAG_NAMESPACE
; break;
989 case DECL_STRUCT
: type
= TAG_STRUCT
; break;
990 case DECL_UNION
: type
= TAG_UNION
; break;
992 default: Assert ("Unexpected declaration" == NULL
); break;
997 static const char* accessField (const statementInfo
*const st
)
999 const char* result
= NULL
;
1001 if ((isLanguage (Lang_cpp
) || isLanguage (Lang_d
) || isLanguage (Lang_ferite
)) &&
1002 st
->scope
== SCOPE_FRIEND
)
1004 else if (st
->member
.access
!= ACCESS_UNDEFINED
)
1005 result
= accessString (st
->member
.access
);
1009 static void addOtherFields (tagEntryInfo
* const tag
, const tagType type
,
1010 const statementInfo
*const st
, vString
*const scope
)
1012 /* For selected tag types, append an extension flag designating the
1013 * parent object in which the tag is defined.
1021 case TAG_ENUMERATOR
:
1031 if (vStringLength (scope
) > 0 &&
1032 (isMember (st
) || st
->parent
->declaration
== DECL_NAMESPACE
))
1034 if (isType (st
->context
, TOKEN_NAME
))
1035 tag
->extensionFields
.scope
[0] = tagName (TAG_CLASS
);
1037 tag
->extensionFields
.scope
[0] =
1038 tagName (declToTagType (parentDecl (st
)));
1039 tag
->extensionFields
.scope
[1] = vStringValue (scope
);
1041 if ((type
== TAG_CLASS
|| type
== TAG_INTERFACE
||
1042 type
== TAG_STRUCT
) && vStringLength (st
->parentClasses
) > 0)
1045 tag
->extensionFields
.inheritance
=
1046 vStringValue (st
->parentClasses
);
1048 if (st
->implementation
!= IMP_DEFAULT
&&
1049 (isLanguage (Lang_cpp
) || isLanguage (Lang_csharp
) ||
1050 isLanguage (Lang_java
) || isLanguage (Lang_d
) || isLanguage (Lang_ferite
)))
1052 tag
->extensionFields
.implementation
=
1053 implementationString (st
->implementation
);
1057 tag
->extensionFields
.access
= accessField (st
);
1059 if ((TRUE
== st
->gotArgs
) && (TRUE
== Option
.extensionFields
.argList
) &&
1060 ((TAG_FUNCTION
== type
) || (TAG_METHOD
== type
) || (TAG_PROTOTYPE
== type
))) {
1061 tag
->extensionFields
.arglist
= getArglistFromPos(tag
->filePosition
, tag
->name
);
1066 if ((TAG_FIELD
== tag
->type
) || (TAG_MEMBER
== tag
->type
) ||
1067 (TAG_EXTERN_VAR
== tag
->type
) || (TAG_TYPEDEF
== tag
->type
) ||
1068 (TAG_VARIABLE
== tag
->type
) || (TAG_METHOD
== tag
->type
) ||
1069 (TAG_PROTOTYPE
== tag
->type
) || (TAG_FUNCTION
== tag
->type
))
1071 if (((TOKEN_NAME
== st
->firstToken
->type
) || isDataTypeKeyword(st
->firstToken
))
1072 && (0 != strcmp(vStringValue(st
->firstToken
->name
), tag
->name
)))
1073 tag
->extensionFields
.varType
= getVarType(st
);
1077 static const char *getVarType (const statementInfo
*const st
)
1079 static vString
*vt
= NULL
;
1083 return vStringValue(st
->firstToken
->name
); /* ignore non-functions */
1090 for (i
= 0; i
< st
->tokenIndex
; i
++)
1092 tokenInfo
*t
= st
->token
[i
];
1096 case TOKEN_NAME
: /* user typename */
1097 if (strcmp(vStringValue(t
->name
), vStringValue(st
->firstToken
->name
)) != 0)
1101 if (t
->keyword
!= KEYWORD_EXTERN
&& t
->keyword
!= KEYWORD_STATIC
) /* uninteresting keywords */
1104 case TOKEN_STAR
: vStringCatS(vt
, " *"); continue;
1105 case TOKEN_ARRAY
: vStringCatS(vt
, "[]"); continue;
1108 if (vStringLength(vt
) > 0)
1109 if (isalpha(vStringValue(vt
)[vStringLength(vt
) - 1]))
1110 vStringPut(vt
, ' ');
1111 vStringCat(vt
, t
->name
);
1113 vStringTerminate(vt
);
1114 return vStringValue(vt
);
1117 static void addContextSeparator (vString
*const scope
)
1119 if (isLanguage (Lang_c
) || isLanguage (Lang_cpp
))
1120 vStringCatS (scope
, "::");
1121 else if (isLanguage (Lang_java
) ||
1122 isLanguage (Lang_d
) || isLanguage (Lang_ferite
) || isLanguage (Lang_csharp
))
1123 vStringCatS (scope
, ".");
1126 static void findScopeHierarchy (vString
*const string
,
1127 const statementInfo
*const st
)
1129 const char* const anon
= "<anonymous>";
1130 boolean nonAnonPresent
= FALSE
;
1132 vStringClear (string
);
1133 if (isType (st
->context
, TOKEN_NAME
))
1135 vStringCopy (string
, st
->context
->name
);
1136 nonAnonPresent
= TRUE
;
1138 if (st
->parent
!= NULL
)
1140 vString
*temp
= vStringNew ();
1141 const statementInfo
*s
;
1143 for (s
= st
->parent
; s
!= NULL
; s
= s
->parent
)
1145 if (isContextualStatement (s
))
1147 vStringCopy (temp
, string
);
1148 vStringClear (string
);
1149 if (isType (s
->blockName
, TOKEN_NAME
))
1151 if (isType (s
->context
, TOKEN_NAME
) &&
1152 vStringLength (s
->context
->name
) > 0)
1154 vStringCat (string
, s
->context
->name
);
1155 addContextSeparator (string
);
1157 vStringCat (string
, s
->blockName
->name
);
1158 nonAnonPresent
= TRUE
;
1161 vStringCopyS (string
, anon
);
1162 if (vStringLength (temp
) > 0)
1163 addContextSeparator (string
);
1164 vStringCat (string
, temp
);
1167 vStringDelete (temp
);
1169 if (! nonAnonPresent
)
1170 vStringClear (string
);
1174 static void makeExtraTagEntry (const tagType type
, tagEntryInfo
*const e
,
1175 vString
*const scope
)
1177 if (Option
.include
.qualifiedTags
&&
1178 scope
!= NULL
&& vStringLength (scope
) > 0)
1180 vString
*const scopedName
= vStringNew ();
1182 if (type
!= TAG_ENUMERATOR
)
1183 vStringCopy (scopedName
, scope
);
1186 /* remove last component (i.e. enumeration name) from scope */
1187 const char* const sc
= vStringValue (scope
);
1188 const char* colon
= strrchr (sc
, ':');
1191 while (*colon
== ':' && colon
> sc
)
1193 vStringNCopy (scopedName
, scope
, colon
+ 1 - sc
);
1196 if (vStringLength (scopedName
) > 0)
1198 addContextSeparator (scopedName
);
1199 vStringCatS (scopedName
, e
->name
);
1200 e
->name
= vStringValue (scopedName
);
1203 vStringDelete (scopedName
);
1207 static void makeTag (const tokenInfo
*const token
,
1208 const statementInfo
*const st
,
1209 boolean isFileScope
, const tagType type
)
1213 fprintf(stderr
, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
1216 /* Nothing is really of file scope when it appears in a header file.
1218 isFileScope
= (boolean
) (isFileScope
&& ! isHeaderFile ());
1220 if (isType (token
, TOKEN_NAME
) && vStringLength (token
->name
) > 0 /* &&
1221 includeTag (type, isFileScope) */)
1223 vString
*scope
= vStringNew ();
1226 /* take only functions which are introduced by "function ..." */
1227 if (type
== TAG_FUNCTION
&& isLanguage (Lang_ferite
) &&
1228 strncmp("function", st
->firstToken
->name
->buffer
, 8) != 0)
1233 initTagEntry (&e
, vStringValue (token
->name
));
1235 e
.lineNumber
= token
->lineNumber
;
1236 e
.filePosition
= token
->filePosition
;
1237 e
.isFileScope
= isFileScope
;
1238 e
.kindName
= tagName (type
);
1239 e
.kind
= tagLetter (type
);
1242 findScopeHierarchy (scope
, st
);
1243 addOtherFields (&e
, type
, st
, scope
);
1249 if (NULL
!= TagEntryFunction
)
1250 makeExtraTagEntry (type
, &e
, scope
);
1251 vStringDelete (scope
);
1252 if (NULL
!= e
.extensionFields
.arglist
)
1253 free((char *) e
.extensionFields
.arglist
);
1257 static boolean
isValidTypeSpecifier (const declType declaration
)
1260 switch (declaration
)
1277 static void qualifyEnumeratorTag (const statementInfo
*const st
,
1278 const tokenInfo
*const nameToken
)
1280 if (isType (nameToken
, TOKEN_NAME
))
1281 makeTag (nameToken
, st
, TRUE
, TAG_ENUMERATOR
);
1284 static void qualifyFunctionTag (const statementInfo
*const st
,
1285 const tokenInfo
*const nameToken
)
1287 if (isType (nameToken
, TOKEN_NAME
))
1289 const tagType type
= (isLanguage (Lang_java
) || isLanguage (Lang_csharp
))
1290 ? TAG_METHOD
: TAG_FUNCTION
;
1291 const boolean isFileScope
=
1292 (boolean
) (st
->member
.access
== ACCESS_PRIVATE
||
1293 (!isMember (st
) && st
->scope
== SCOPE_STATIC
));
1295 makeTag (nameToken
, st
, isFileScope
, type
);
1299 static void qualifyFunctionDeclTag (const statementInfo
*const st
,
1300 const tokenInfo
*const nameToken
)
1302 if (! isType (nameToken
, TOKEN_NAME
))
1304 else if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
))
1305 qualifyFunctionTag (st
, nameToken
);
1306 else if (st
->scope
== SCOPE_TYPEDEF
)
1307 makeTag (nameToken
, st
, TRUE
, TAG_TYPEDEF
);
1308 else if (isValidTypeSpecifier (st
->declaration
) && ! isLanguage (Lang_csharp
))
1309 makeTag (nameToken
, st
, TRUE
, TAG_PROTOTYPE
);
1312 static void qualifyCompoundTag (const statementInfo
*const st
,
1313 const tokenInfo
*const nameToken
)
1315 if (isType (nameToken
, TOKEN_NAME
))
1317 const tagType type
= declToTagType (st
->declaration
);
1319 if (type
!= TAG_UNDEFINED
)
1320 makeTag (nameToken
, st
, (boolean
) (! isLanguage (Lang_java
) && ! isLanguage (Lang_csharp
)), type
);
1324 static void qualifyBlockTag (statementInfo
*const st
,
1325 const tokenInfo
*const nameToken
)
1327 switch (st
->declaration
)
1331 case DECL_INTERFACE
:
1332 case DECL_NAMESPACE
:
1335 qualifyCompoundTag (st
, nameToken
);
1341 static void qualifyVariableTag (const statementInfo
*const st
,
1342 const tokenInfo
*const nameToken
)
1344 /* We have to watch that we do not interpret a declaration of the
1345 * form "struct tag;" as a variable definition. In such a case, the
1346 * token preceding the name will be a keyword.
1348 if (! isType (nameToken
, TOKEN_NAME
))
1350 else if (st
->declaration
== DECL_IGNORE
)
1352 else if (st
->scope
== SCOPE_TYPEDEF
)
1353 makeTag (nameToken
, st
, TRUE
, TAG_TYPEDEF
);
1354 else if (st
->declaration
== DECL_PACKAGE
)
1355 makeTag (nameToken
, st
, FALSE
, TAG_PACKAGE
);
1356 else if (st
->declaration
== DECL_MODULE
) /* handle modules in D as namespaces */
1357 makeTag (nameToken
, st
, FALSE
, TAG_NAMESPACE
);
1358 else if (isValidTypeSpecifier (st
->declaration
))
1362 if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
))
1363 makeTag (nameToken
, st
,
1364 (boolean
) (st
->member
.access
== ACCESS_PRIVATE
),
1366 else if (st
->scope
== SCOPE_GLOBAL
|| st
->scope
== SCOPE_STATIC
)
1367 makeTag (nameToken
, st
, TRUE
, TAG_MEMBER
);
1371 if (st
->scope
== SCOPE_EXTERN
|| ! st
->haveQualifyingName
)
1372 makeTag (nameToken
, st
, FALSE
, TAG_EXTERN_VAR
);
1374 makeTag (nameToken
, st
, (boolean
) (st
->scope
== SCOPE_STATIC
),
1384 static int skipToOneOf (const char *const chars
)
1389 while (c
!= EOF
&& c
!= '\0' && strchr (chars
, c
) == NULL
);
1393 /* Skip to the next non-white character.
1395 static int skipToNonWhite (void)
1403 while (isspace (c
));
1408 /* Skips to the next brace in column 1. This is intended for cases where
1409 * preprocessor constructs result in unbalanced braces.
1411 static void skipToFormattedBraceMatch (void)
1417 while (c
!= EOF
&& (c
!= '\n' || next
!= '}'))
1424 /* Skip to the matching character indicated by the pair string. If skipping
1425 * to a matching brace and any brace is found within a different level of a
1426 * #if conditional statement while brace formatting is in effect, we skip to
1427 * the brace matched by its formatting. It is assumed that we have already
1428 * read the character which starts the group (i.e. the first character of
1431 static void skipToMatch (const char *const pair
)
1433 const boolean braceMatching
= (boolean
) (strcmp ("{}", pair
) == 0);
1434 const boolean braceFormatting
= (boolean
) (isBraceFormat () && braceMatching
);
1435 const unsigned int initialLevel
= getDirectiveNestLevel ();
1436 const int begin
= pair
[0], end
= pair
[1];
1437 const unsigned long inputLineNumber
= getInputLineNumber ();
1440 while (matchLevel
> 0 && (c
= cppGetc ()) != EOF
)
1445 if (braceFormatting
&& getDirectiveNestLevel () != initialLevel
)
1447 skipToFormattedBraceMatch ();
1454 if (braceFormatting
&& getDirectiveNestLevel () != initialLevel
)
1456 skipToFormattedBraceMatch ();
1463 verbose ("%s: failed to find match for '%c' at line %lu\n",
1464 getInputFileName (), begin
, inputLineNumber
);
1466 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
1468 longjmp (Exception
, (int) ExceptionFormattingError
);
1472 static void skipParens (void)
1474 const int c
= skipToNonWhite ();
1482 static void skipBraces (void)
1484 const int c
= skipToNonWhite ();
1492 static keywordId
analyzeKeyword (const char *const name
)
1494 const keywordId id
= (keywordId
) lookupKeyword (name
, getSourceLanguage ());
1498 static void analyzeIdentifier (tokenInfo
*const token
)
1500 char *const name
= vStringValue (token
->name
);
1501 const char *replacement
= NULL
;
1502 boolean parensToo
= FALSE
;
1504 if (isLanguage (Lang_java
) ||
1505 ! isIgnoreToken (name
, &parensToo
, &replacement
))
1507 if (replacement
!= NULL
)
1508 token
->keyword
= analyzeKeyword (replacement
);
1510 token
->keyword
= analyzeKeyword (vStringValue (token
->name
));
1512 if (token
->keyword
== KEYWORD_NONE
)
1513 token
->type
= TOKEN_NAME
;
1515 token
->type
= TOKEN_KEYWORD
;
1522 int c
= skipToNonWhite ();
1530 static void readIdentifier (tokenInfo
*const token
, const int firstChar
)
1532 vString
*const name
= token
->name
;
1537 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1538 * the ~ and the class name. */
1539 if (isLanguage (Lang_cpp
) && firstChar
== '~')
1541 vStringPut (name
, c
);
1542 c
= skipToNonWhite ();
1547 vStringPut (name
, c
);
1549 } while (isident (c
));
1550 vStringTerminate (name
);
1551 cppUngetc (c
); /* unget non-identifier character */
1553 analyzeIdentifier (token
);
1556 static void readPackageName (tokenInfo
*const token
, const int firstChar
)
1558 vString
*const name
= token
->name
;
1563 while (isident (c
) || c
== '.')
1565 vStringPut (name
, c
);
1568 vStringTerminate (name
);
1569 cppUngetc (c
); /* unget non-package character */
1572 static void readPackageOrNamespace (statementInfo
*const st
, const declType declaration
)
1574 st
->declaration
= declaration
;
1576 if (declaration
== DECL_NAMESPACE
&& !isLanguage (Lang_csharp
))
1578 /* In C++ a namespace is specified one level at a time. */
1583 /* In C#, a namespace can also be specified like a Java package name. */
1584 tokenInfo
*const token
= activeToken (st
);
1585 Assert (isType (token
, TOKEN_KEYWORD
));
1586 readPackageName (token
, skipToNonWhite ());
1587 token
->type
= TOKEN_NAME
;
1589 st
->haveQualifyingName
= TRUE
;
1593 static void readPackage (statementInfo
*const st
)
1595 tokenInfo
*const token
= activeToken (st
);
1596 Assert (isType (token
, TOKEN_KEYWORD
));
1597 readPackageName (token
, skipToNonWhite ());
1598 token
->type
= TOKEN_NAME
;
1599 if (isLanguage (Lang_d
))
1600 st
->declaration
= DECL_MODULE
;
1602 st
->declaration
= DECL_PACKAGE
;
1604 st
->haveQualifyingName
= TRUE
;
1607 static void processName (statementInfo
*const st
)
1609 Assert (isType (activeToken (st
), TOKEN_NAME
));
1610 if (st
->gotName
&& st
->declaration
== DECL_NONE
)
1611 st
->declaration
= DECL_BASE
;
1613 st
->haveQualifyingName
= TRUE
;
1616 static void readOperator (statementInfo
*const st
)
1618 const char *const acceptable
= "+-*/%^&|~!=<>,[]";
1619 const tokenInfo
* const prev
= prevToken (st
,1);
1620 tokenInfo
*const token
= activeToken (st
);
1621 vString
*const name
= token
->name
;
1622 int c
= skipToNonWhite ();
1624 /* When we arrive here, we have the keyword "operator" in 'name'.
1626 if (isType (prev
, TOKEN_KEYWORD
) && (prev
->keyword
== KEYWORD_ENUM
||
1627 prev
->keyword
== KEYWORD_STRUCT
|| prev
->keyword
== KEYWORD_UNION
))
1628 ; /* ignore "operator" keyword if preceded by these keywords */
1631 /* Verify whether this is a valid function call (i.e. "()") operator.
1633 if (cppGetc () == ')')
1635 vStringPut (name
, ' '); /* always separate operator from keyword */
1636 c
= skipToNonWhite ();
1638 vStringCatS (name
, "()");
1646 else if (isident1 (c
))
1648 /* Handle "new" and "delete" operators, and conversion functions
1649 * (per 13.3.1.1.2 [2] of the C++ spec).
1651 boolean whiteSpace
= TRUE
; /* default causes insertion of space */
1660 vStringPut (name
, ' ');
1663 vStringPut (name
, c
);
1666 } while (! isOneOf (c
, "(;") && c
!= EOF
);
1667 vStringTerminate (name
);
1669 else if (isOneOf (c
, acceptable
))
1671 vStringPut (name
, ' '); /* always separate operator from keyword */
1674 vStringPut (name
, c
);
1676 } while (isOneOf (c
, acceptable
));
1677 vStringTerminate (name
);
1682 token
->type
= TOKEN_NAME
;
1683 token
->keyword
= KEYWORD_NONE
;
1687 static void copyToken (tokenInfo
*const dest
, const tokenInfo
*const src
)
1689 dest
->type
= src
->type
;
1690 dest
->keyword
= src
->keyword
;
1691 dest
->filePosition
= src
->filePosition
;
1692 dest
->lineNumber
= src
->lineNumber
;
1693 vStringCopy (dest
->name
, src
->name
);
1696 static void setAccess (statementInfo
*const st
, const accessType laccess
)
1700 if (isLanguage (Lang_cpp
) || isLanguage (Lang_d
) || isLanguage (Lang_ferite
))
1702 int c
= skipToNonWhite ();
1705 reinitStatementWithToken (st
, prevToken (st
, 1), FALSE
);
1709 st
->member
.accessDefault
= laccess
;
1711 st
->member
.access
= laccess
;
1715 static void discardTypeList (tokenInfo
*const token
)
1717 int c
= skipToNonWhite ();
1718 while (isident1 (c
))
1720 readIdentifier (token
, c
);
1721 c
= skipToNonWhite ();
1722 if (c
== '.' || c
== ',')
1723 c
= skipToNonWhite ();
1728 static void addParentClass (statementInfo
*const st
, tokenInfo
*const token
)
1730 if (vStringLength (token
->name
) > 0 &&
1731 vStringLength (st
->parentClasses
) > 0)
1733 vStringPut (st
->parentClasses
, ',');
1735 vStringCat (st
->parentClasses
, token
->name
);
1738 static void readParents (statementInfo
*const st
, const int qualifier
)
1740 tokenInfo
*const token
= newToken ();
1741 tokenInfo
*const parent
= newToken ();
1746 c
= skipToNonWhite ();
1749 readIdentifier (token
, c
);
1750 if (isType (token
, TOKEN_NAME
))
1751 vStringCat (parent
->name
, token
->name
);
1754 addParentClass (st
, parent
);
1758 else if (c
== qualifier
)
1759 vStringPut (parent
->name
, c
);
1762 else if (isType (token
, TOKEN_NAME
))
1764 addParentClass (st
, parent
);
1767 } while (c
!= '{' && c
!= EOF
);
1769 deleteToken (parent
);
1770 deleteToken (token
);
1773 static void processToken (tokenInfo
*const token
, statementInfo
*const st
)
1775 switch (token
->keyword
) /* is it a reserved word? */
1779 case KEYWORD_NONE
: processName (st
); break;
1780 case KEYWORD_ABSTRACT
: st
->implementation
= IMP_ABSTRACT
; break;
1781 case KEYWORD_ATTRIBUTE
: skipParens (); initToken (token
); break;
1782 case KEYWORD_CATCH
: skipParens (); skipBraces (); break;
1783 case KEYWORD_CHAR
: st
->declaration
= DECL_BASE
; break;
1784 case KEYWORD_CLASS
: st
->declaration
= DECL_CLASS
; break;
1785 case KEYWORD_CONST
: st
->declaration
= DECL_BASE
; break;
1786 case KEYWORD_DOUBLE
: st
->declaration
= DECL_BASE
; break;
1787 case KEYWORD_ENUM
: st
->declaration
= DECL_ENUM
; break;
1788 case KEYWORD_EXTENDS
: readParents (st
, '.');
1789 setToken (st
, TOKEN_NONE
); break;
1790 case KEYWORD_FLOAT
: st
->declaration
= DECL_BASE
; break;
1791 case KEYWORD_FRIEND
: st
->scope
= SCOPE_FRIEND
; break;
1792 case KEYWORD_IMPLEMENTS
:readParents (st
, '.');
1793 setToken (st
, TOKEN_NONE
); break;
1794 case KEYWORD_IMPORT
: st
->declaration
= DECL_IGNORE
; break;
1795 case KEYWORD_INT
: st
->declaration
= DECL_BASE
; break;
1796 case KEYWORD_BOOLEAN
: st
->declaration
= DECL_BASE
; break;
1797 case KEYWORD_WCHAR_T
: st
->declaration
= DECL_BASE
; break;
1798 case KEYWORD_SIZE_T
: st
->declaration
= DECL_BASE
; break;
1799 case KEYWORD_INTERFACE
: st
->declaration
= DECL_INTERFACE
; break;
1800 case KEYWORD_LONG
: st
->declaration
= DECL_BASE
; break;
1801 case KEYWORD_OPERATOR
: readOperator (st
); break;
1802 case KEYWORD_MODULE
: readPackage (st
); break;
1803 case KEYWORD_PRIVATE
: setAccess (st
, ACCESS_PRIVATE
); break;
1804 case KEYWORD_PROTECTED
: setAccess (st
, ACCESS_PROTECTED
); break;
1805 case KEYWORD_PUBLIC
: setAccess (st
, ACCESS_PUBLIC
); break;
1806 case KEYWORD_SHORT
: st
->declaration
= DECL_BASE
; break;
1807 case KEYWORD_SIGNED
: st
->declaration
= DECL_BASE
; break;
1808 case KEYWORD_STRUCT
: st
->declaration
= DECL_STRUCT
; break;
1809 case KEYWORD_THROWS
: discardTypeList (token
); break;
1810 case KEYWORD_TYPEDEF
: st
->scope
= SCOPE_TYPEDEF
; break;
1811 case KEYWORD_UNION
: st
->declaration
= DECL_UNION
; break;
1812 case KEYWORD_UNSIGNED
: st
->declaration
= DECL_BASE
; break;
1813 case KEYWORD_USING
: st
->declaration
= DECL_IGNORE
; break;
1814 case KEYWORD_VOID
: st
->declaration
= DECL_BASE
; break;
1815 case KEYWORD_VOLATILE
: st
->declaration
= DECL_BASE
; break;
1816 case KEYWORD_VIRTUAL
: st
->implementation
= IMP_VIRTUAL
; break;
1818 case KEYWORD_NAMESPACE
: readPackageOrNamespace (st
, DECL_NAMESPACE
); break;
1819 case KEYWORD_PACKAGE
: readPackageOrNamespace (st
, DECL_PACKAGE
); break;
1821 if (isLanguage (Lang_csharp
))
1822 st
->declaration
= DECL_EVENT
;
1825 case KEYWORD_EXTERN
:
1826 if (! isLanguage (Lang_csharp
) || !st
->gotName
)
1828 /*reinitStatement (st, FALSE);*/
1829 st
->scope
= SCOPE_EXTERN
;
1830 st
->declaration
= DECL_BASE
;
1834 case KEYWORD_STATIC
:
1835 if (! isLanguage (Lang_java
) && ! isLanguage (Lang_csharp
))
1837 /*reinitStatement (st, FALSE);*/
1838 st
->scope
= SCOPE_STATIC
;
1839 st
->declaration
= DECL_BASE
;
1846 * Parenthesis handling functions
1849 static void restartStatement (statementInfo
*const st
)
1851 tokenInfo
*const save
= newToken ();
1852 tokenInfo
*token
= activeToken (st
);
1854 copyToken (save
, token
);
1855 DebugStatement ( if (debug (DEBUG_PARSE
)) printf ("<ES>");)
1856 reinitStatement (st
, FALSE
);
1857 token
= activeToken (st
);
1858 copyToken (token
, save
);
1860 processToken (token
, st
);
1863 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
1865 * mem-initializer-list:
1866 * mem-initializer, mem-initializer-list
1869 * [::] [nested-name-spec] class-name (...)
1872 static void skipMemIntializerList (tokenInfo
*const token
)
1878 c
= skipToNonWhite ();
1879 while (isident1 (c
) || c
== ':')
1882 readIdentifier (token
, c
);
1883 c
= skipToNonWhite ();
1888 c
= skipToNonWhite ();
1893 c
= skipToNonWhite ();
1899 static void skipMacro (statementInfo
*const st
)
1901 tokenInfo
*const prev2
= prevToken (st
, 2);
1903 if (isType (prev2
, TOKEN_NAME
))
1908 /* Skips over characters following the parameter list. This will be either
1909 * non-ANSI style function declarations or C++ stuff. Our choices:
1913 * int func (one, two) int one; float two; {...}
1915 * int func (int one, float two);
1916 * int func (int one, float two) {...}
1918 * int foo (...) [const|volatile] [throw (...)];
1919 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
1920 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
1923 static boolean
skipPostArgumentStuff (statementInfo
*const st
,
1924 parenInfo
*const info
)
1926 tokenInfo
*const token
= activeToken (st
);
1927 unsigned int parameters
= info
->parameterCount
;
1928 unsigned int elementCount
= 0;
1929 boolean restart
= FALSE
;
1930 boolean end
= FALSE
;
1931 int c
= skipToNonWhite ();
1938 case ':': skipMemIntializerList (token
);break; /* ctor-initializer */
1939 case '[': skipToMatch ("[]"); break;
1940 case '=': cppUngetc (c
); end
= TRUE
; break;
1941 case '{': cppUngetc (c
); end
= TRUE
; break;
1942 case '}': cppUngetc (c
); end
= TRUE
; break;
1945 if (elementCount
> 0)
1951 if (parameters
== 0 || elementCount
< 2)
1956 else if (--parameters
== 0)
1963 readIdentifier (token
, c
);
1964 switch (token
->keyword
)
1966 case KEYWORD_ATTRIBUTE
: skipParens (); break;
1967 case KEYWORD_THROW
: skipParens (); break;
1968 case KEYWORD_CONST
: break;
1969 case KEYWORD_TRY
: break;
1970 case KEYWORD_VOLATILE
: break;
1972 case KEYWORD_CATCH
: case KEYWORD_CLASS
:
1973 case KEYWORD_EXPLICIT
: case KEYWORD_EXTERN
:
1974 case KEYWORD_FRIEND
: case KEYWORD_INLINE
:
1975 case KEYWORD_MUTABLE
: case KEYWORD_NAMESPACE
:
1976 case KEYWORD_NEW
: case KEYWORD_OPERATOR
:
1977 case KEYWORD_OVERLOAD
: case KEYWORD_PRIVATE
:
1978 case KEYWORD_PROTECTED
: case KEYWORD_PUBLIC
:
1979 case KEYWORD_STATIC
: case KEYWORD_TEMPLATE
:
1980 case KEYWORD_TYPEDEF
: case KEYWORD_TYPENAME
:
1981 case KEYWORD_USING
: case KEYWORD_VIRTUAL
:
1982 /* Never allowed within parameter declarations.
1989 if (isType (token
, TOKEN_NONE
))
1991 else if (info
->isKnrParamList
&& info
->parameterCount
> 0)
1995 /* If we encounter any other identifier immediately
1996 * following an empty parameter list, this is almost
1997 * certainly one of those Microsoft macro "thingies"
1998 * that the automatic source code generation sticks
1999 * in. Terminate the current statement.
2010 c
= skipToNonWhite ();
2017 restartStatement (st
);
2019 setToken (st
, TOKEN_NONE
);
2020 return (boolean
) (c
!= EOF
);
2023 static void skipJavaThrows (statementInfo
*const st
)
2025 tokenInfo
*const token
= activeToken (st
);
2026 int c
= skipToNonWhite ();
2030 readIdentifier (token
, c
);
2031 if (token
->keyword
== KEYWORD_THROWS
)
2035 c
= skipToNonWhite ();
2038 readIdentifier (token
, c
);
2039 c
= skipToNonWhite ();
2041 } while (c
== '.' || c
== ',');
2045 setToken (st
, TOKEN_NONE
);
2048 static void analyzePostParens (statementInfo
*const st
, parenInfo
*const info
)
2050 const unsigned long inputLineNumber
= getInputLineNumber ();
2051 int c
= skipToNonWhite ();
2054 if (isOneOf (c
, "{;,="))
2056 else if (isLanguage (Lang_java
))
2057 skipJavaThrows (st
);
2060 if (! skipPostArgumentStuff (st
, info
))
2063 "%s: confusing argument declarations beginning at line %lu\n",
2064 getInputFileName (), inputLineNumber
);
2065 longjmp (Exception
, (int) ExceptionFormattingError
);
2070 static int parseParens (statementInfo
*const st
, parenInfo
*const info
)
2072 tokenInfo
*const token
= activeToken (st
);
2073 unsigned int identifierCount
= 0;
2074 unsigned int depth
= 1;
2075 boolean firstChar
= TRUE
;
2076 int nextChar
= '\0';
2078 info
->parameterCount
= 1;
2081 int c
= skipToNonWhite ();
2087 /* DEBUG_PRINT("parseParens, po++\n"); */
2088 info
->isKnrParamList
= FALSE
;
2089 if (identifierCount
== 0)
2090 info
->isParamList
= FALSE
;
2095 info
->isKnrParamList
= FALSE
;
2099 info
->isNameCandidate
= FALSE
;
2100 info
->isKnrParamList
= FALSE
;
2104 info
->isNameCandidate
= FALSE
;
2105 if (info
->isKnrParamList
)
2107 ++info
->parameterCount
;
2108 identifierCount
= 0;
2113 info
->isKnrParamList
= FALSE
;
2114 info
->isNameCandidate
= FALSE
;
2117 info
->isParamList
= FALSE
;
2124 info
->isKnrParamList
= FALSE
;
2129 info
->isKnrParamList
= FALSE
;
2135 info
->parameterCount
= 0;
2140 info
->isKnrParamList
= FALSE
;
2143 info
->isNameCandidate
= FALSE
;
2148 else if (isType (token
, TOKEN_PAREN_NAME
))
2150 c
= skipToNonWhite ();
2151 if (c
== '*') /* check for function pointer */
2154 c
= skipToNonWhite ();
2162 info
->nestedArgs
= TRUE
;
2172 if (++identifierCount
> 1)
2173 info
->isKnrParamList
= FALSE
;
2174 readIdentifier (token
, c
);
2175 if (isType (token
, TOKEN_NAME
) && info
->isNameCandidate
)
2176 token
->type
= TOKEN_PAREN_NAME
;
2177 else if (isType (token
, TOKEN_KEYWORD
))
2179 info
->isKnrParamList
= FALSE
;
2180 info
->isNameCandidate
= FALSE
;
2185 info
->isParamList
= FALSE
;
2186 info
->isKnrParamList
= FALSE
;
2187 info
->isNameCandidate
= FALSE
;
2188 info
->invalidContents
= TRUE
;
2193 } while (! info
->nestedArgs
&& depth
> 0 &&
2194 (info
->isKnrParamList
|| info
->isNameCandidate
));
2196 if (! info
->nestedArgs
) while (depth
> 0)
2201 if (st
->argEndPosition
== 0)
2202 st
->argEndPosition
= ftell(File
.fp
);
2204 if (! info
->isNameCandidate
)
2210 static void initParenInfo (parenInfo
*const info
)
2212 info
->isParamList
= TRUE
;
2213 info
->isKnrParamList
= TRUE
;
2214 info
->isNameCandidate
= TRUE
;
2215 info
->invalidContents
= FALSE
;
2216 info
->nestedArgs
= FALSE
;
2217 info
->parameterCount
= 0;
2220 static void analyzeParens (statementInfo
*const st
)
2222 tokenInfo
*const prev
= prevToken (st
, 1);
2224 if (! isType (prev
, TOKEN_NONE
)) /* in case of ignored enclosing macros */
2226 tokenInfo
*const token
= activeToken (st
);
2230 initParenInfo (&info
);
2231 parseParens (st
, &info
);
2233 c
= skipToNonWhite ();
2236 if (info
.invalidContents
)
2238 reinitStatement (st
, FALSE
);
2240 else if (info
.isNameCandidate
&& isType (token
, TOKEN_PAREN_NAME
) &&
2241 ! st
->gotParenName
&&
2242 (! info
.isParamList
|| ! st
->haveQualifyingName
||
2244 (c
== '=' && st
->implementation
!= IMP_VIRTUAL
) ||
2245 (st
->declaration
== DECL_NONE
&& isOneOf (c
, ",;"))))
2247 token
->type
= TOKEN_NAME
;
2249 st
->gotParenName
= TRUE
;
2251 else if (! st
->gotArgs
&& info
.isParamList
)
2254 setToken (st
, TOKEN_ARGS
);
2256 analyzePostParens (st
, &info
);
2260 setToken (st
, TOKEN_NONE
);
2266 * Token parsing functions
2269 static void addContext (statementInfo
*const st
, const tokenInfo
* const token
)
2271 if (isType (token
, TOKEN_NAME
))
2273 if (vStringLength (st
->context
->name
) > 0)
2275 if (isLanguage (Lang_c
) || isLanguage (Lang_cpp
))
2276 vStringCatS (st
->context
->name
, "::");
2277 else if (isLanguage (Lang_java
) ||
2278 isLanguage (Lang_d
) || isLanguage (Lang_ferite
) || isLanguage (Lang_csharp
))
2279 vStringCatS (st
->context
->name
, ".");
2281 vStringCat (st
->context
->name
, token
->name
);
2282 st
->context
->type
= TOKEN_NAME
;
2286 static boolean
inheritingDeclaration (declType decl
)
2289 decl
== DECL_CLASS
||
2290 decl
== DECL_STRUCT
||
2291 decl
== DECL_INTERFACE
);
2294 static void processColon (statementInfo
*const st
)
2296 int c
= skipToNonWhite ();
2297 const boolean doubleColon
= (boolean
) (c
== ':');
2301 setToken (st
, TOKEN_DOUBLE_COLON
);
2302 st
->haveQualifyingName
= FALSE
;
2307 if (((isLanguage (Lang_cpp
) || isLanguage (Lang_csharp
)) &&
2308 inheritingDeclaration (st
->declaration
)) ||
2309 isLanguage (Lang_d
))
2311 readParents (st
, ':');
2313 else if (parentDecl (st
) == DECL_STRUCT
)
2315 c
= skipToOneOf (",;");
2317 setToken (st
, TOKEN_COMMA
);
2319 setToken (st
, TOKEN_SEMICOLON
);
2323 const tokenInfo
*const prev
= prevToken (st
, 1);
2324 const tokenInfo
*const prev2
= prevToken (st
, 2);
2325 if (prev
->keyword
== KEYWORD_DEFAULT
||
2326 prev2
->keyword
== KEYWORD_CASE
||
2329 reinitStatement (st
, FALSE
);
2335 /* Skips over any initializing value which may follow an '=' character in a
2336 * variable definition.
2338 static int skipInitializer (statementInfo
*const st
)
2340 boolean done
= FALSE
;
2345 c
= skipToNonWhite ();
2348 longjmp (Exception
, (int) ExceptionFormattingError
);
2352 case ';': done
= TRUE
; break;
2355 if (st
->implementation
== IMP_VIRTUAL
)
2356 st
->implementation
= IMP_PURE_VIRTUAL
;
2359 case '[': skipToMatch ("[]"); break;
2360 case '(': skipToMatch ("()"); break;
2361 case '{': skipToMatch ("{}"); break;
2364 if (insideEnumBody (st
))
2366 else if (! isBraceFormat ())
2368 verbose ("%s: unexpected closing brace at line %lu\n",
2369 getInputFileName (), getInputLineNumber ());
2370 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
2380 static void processInitializer (statementInfo
*const st
)
2382 const boolean inEnumBody
= insideEnumBody (st
);
2383 const int c
= skipInitializer (st
);
2386 setToken (st
, TOKEN_SEMICOLON
);
2388 setToken (st
, TOKEN_COMMA
);
2389 else if (c
== '}' && inEnumBody
)
2392 setToken (st
, TOKEN_COMMA
);
2394 if (st
->scope
== SCOPE_EXTERN
)
2395 st
->scope
= SCOPE_GLOBAL
;
2398 static void parseIdentifier (statementInfo
*const st
, const int c
)
2400 tokenInfo
*const token
= activeToken (st
);
2402 readIdentifier (token
, c
);
2403 if (! isType (token
, TOKEN_NONE
))
2404 processToken (token
, st
);
2407 static void parseGeneralToken (statementInfo
*const st
, const int c
)
2409 const tokenInfo
*const prev
= prevToken (st
, 1);
2413 parseIdentifier (st
, c
);
2414 if (isType (st
->context
, TOKEN_NAME
) &&
2415 isType (activeToken (st
), TOKEN_NAME
) && isType (prev
, TOKEN_NAME
))
2417 initToken (st
->context
);
2420 else if (isExternCDecl (st
, c
))
2422 st
->declaration
= DECL_NOMANGLE
;
2423 st
->scope
= SCOPE_GLOBAL
;
2427 /* Reads characters from the pre-processor and assembles tokens, setting
2428 * the current statement state.
2430 static void nextToken (statementInfo
*const st
)
2433 tokenInfo
*token
= activeToken (st
);
2436 c
= skipToNonWhite();
2439 case EOF
: longjmp (Exception
, (int) ExceptionEOF
); break;
2440 case '(': analyzeParens (st
); token
= activeToken (st
); break;
2441 case '*': setToken (st
, TOKEN_STAR
); break;
2442 case ',': setToken (st
, TOKEN_COMMA
); break;
2443 case ':': processColon (st
); break;
2444 case ';': setToken (st
, TOKEN_SEMICOLON
); break;
2445 case '<': skipToMatch ("<>"); break;
2446 case '=': processInitializer (st
); break;
2447 case '[': setToken (st
, TOKEN_ARRAY
); skipToMatch ("[]"); break;
2448 case '{': setToken (st
, TOKEN_BRACE_OPEN
); break;
2449 case '}': setToken (st
, TOKEN_BRACE_CLOSE
); break;
2450 default: parseGeneralToken (st
, c
); break;
2452 } while (isType (token
, TOKEN_NONE
));
2454 /* We want to know about non-keyword variable types */
2455 if (TOKEN_NONE
== st
->firstToken
->type
)
2457 if ((TOKEN_NAME
== token
->type
) || isDataTypeKeyword(token
)) {
2458 copyToken(st
->firstToken
, token
);
2464 * Scanning support functions
2466 static unsigned int contextual_fake_count
= 0;
2467 static statementInfo
*CurrentStatement
= NULL
;
2469 static statementInfo
*newStatement (statementInfo
*const parent
)
2471 statementInfo
*const st
= xMalloc (1, statementInfo
);
2474 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
2475 st
->token
[i
] = newToken ();
2477 st
->context
= newToken ();
2478 st
->blockName
= newToken ();
2479 st
->parentClasses
= vStringNew ();
2480 st
->firstToken
= newToken();
2482 initStatement (st
, parent
);
2483 CurrentStatement
= st
;
2488 static void deleteStatement (void)
2490 statementInfo
*const st
= CurrentStatement
;
2491 statementInfo
*const parent
= st
->parent
;
2494 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
2496 deleteToken (st
->token
[i
]); st
->token
[i
] = NULL
;
2498 deleteToken (st
->blockName
); st
->blockName
= NULL
;
2499 deleteToken (st
->context
); st
->context
= NULL
;
2500 vStringDelete (st
->parentClasses
); st
->parentClasses
= NULL
;
2501 deleteToken(st
->firstToken
);
2503 CurrentStatement
= parent
;
2506 static void deleteAllStatements (void)
2508 while (CurrentStatement
!= NULL
)
2512 static boolean
isStatementEnd (const statementInfo
*const st
)
2514 const tokenInfo
*const token
= activeToken (st
);
2517 if (isType (token
, TOKEN_SEMICOLON
))
2519 else if (isType (token
, TOKEN_BRACE_CLOSE
))
2520 /* Java, D, C# do not require semicolons to end a block. Neither do C++
2521 * namespaces. All other blocks require a semicolon to terminate them.
2523 isEnd
= (boolean
) (isLanguage (Lang_java
) || isLanguage (Lang_d
) || isLanguage (Lang_csharp
) ||
2524 ! isContextualStatement (st
));
2531 static void checkStatementEnd (statementInfo
*const st
)
2533 const tokenInfo
*const token
= activeToken (st
);
2534 boolean comma
= isType (token
, TOKEN_COMMA
);
2536 if (comma
|| isStatementEnd (st
))
2538 reinitStatementWithToken (st
, activeToken (st
), comma
);
2541 DebugStatement ( if (debug (DEBUG_PARSE
)) printf ("<ES>"); )
2546 cppBeginStatement ();
2551 static void nest (statementInfo
*const st
, const unsigned int nestLevel
)
2553 switch (st
->declaration
)
2557 case DECL_INTERFACE
:
2558 case DECL_NAMESPACE
:
2562 createTags (nestLevel
, st
);
2569 setToken (st
, TOKEN_BRACE_CLOSE
);
2572 static void tagCheck (statementInfo
*const st
)
2574 const tokenInfo
*const token
= activeToken (st
);
2575 const tokenInfo
*const prev
= prevToken (st
, 1);
2576 const tokenInfo
*const prev2
= prevToken (st
, 2);
2578 switch (token
->type
)
2581 if (insideEnumBody (st
))
2582 qualifyEnumeratorTag (st
, token
);
2586 if (st
->haveQualifyingName
)
2587 makeTag (token
, st
, FALSE
, TAG_PACKAGE
);
2590 case TOKEN_BRACE_OPEN
:
2591 if (isType (prev
, TOKEN_ARGS
))
2593 if (st
->haveQualifyingName
)
2595 st
->declaration
= DECL_FUNCTION
;
2596 if (isType (prev2
, TOKEN_NAME
))
2597 copyToken (st
->blockName
, prev2
);
2598 qualifyFunctionTag (st
, prev2
);
2601 else if (isContextualStatement (st
))
2603 tokenInfo
*name_token
= (tokenInfo
*)prev
;
2604 if (isType (name_token
, TOKEN_NAME
))
2606 copyToken (st
->blockName
, name_token
);
2608 else if (isLanguage (Lang_csharp
))
2609 makeTag (prev
, st
, FALSE
, TAG_PROPERTY
);
2612 tokenInfo
*contextual_token
= (tokenInfo
*)prev
;
2613 if(isContextualKeyword (contextual_token
))
2617 name_token
= newToken ();
2618 copyToken (name_token
, contextual_token
);
2620 sprintf(buffer
, "anon_%s_%d", name_token
->name
->buffer
, contextual_fake_count
++);
2621 vStringClear(name_token
->name
);
2622 vStringCatS(name_token
->name
, buffer
);
2624 name_token
->type
= TOKEN_NAME
;
2625 name_token
->keyword
= KEYWORD_NONE
;
2628 contextual_token
= activeToken (st
);
2629 copyToken (contextual_token
, token
);
2630 copyToken ((tokenInfo
*const)token
, name_token
);
2631 copyToken (st
->blockName
, name_token
);
2632 copyToken (st
->firstToken
, name_token
);
2635 qualifyBlockTag (st
, name_token
);
2639 case TOKEN_SEMICOLON
:
2641 if (insideEnumBody (st
))
2643 else if (isType (prev
, TOKEN_NAME
))
2645 if (isContextualKeyword (prev2
))
2646 makeTag (prev
, st
, TRUE
, TAG_EXTERN_VAR
);
2648 qualifyVariableTag (st
, prev
);
2650 else if (isType (prev
, TOKEN_ARGS
) && isType (prev2
, TOKEN_NAME
))
2652 qualifyFunctionDeclTag (st
, prev2
);
2660 /* Parses the current file and decides whether to write out and tags that
2663 static void createTags (const unsigned int nestLevel
,
2664 statementInfo
*const parent
)
2666 statementInfo
*const st
= newStatement (parent
);
2668 DebugStatement ( if (nestLevel
> 0) debugParseNest (TRUE
, nestLevel
); )
2675 token
= activeToken (st
);
2677 if (isType (token
, TOKEN_BRACE_CLOSE
))
2685 verbose ("%s: unexpected closing brace at line %lu\n",
2686 getInputFileName (), getInputLineNumber ());
2687 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
2690 else if (isType (token
, TOKEN_DOUBLE_COLON
))
2692 addContext (st
, prevToken (st
, 1));
2697 tagCheck (st
);/* this can add new token */
2698 if (isType (activeToken (st
), TOKEN_BRACE_OPEN
))
2699 nest (st
, nestLevel
+ 1);
2700 checkStatementEnd (st
);
2704 DebugStatement ( if (nestLevel
> 0) debugParseNest (FALSE
, nestLevel
- 1); )
2707 static boolean
findCTags (const unsigned int passCount
)
2709 exception_t exception
;
2712 Assert (passCount
< 3);
2713 cppInit ((boolean
) (passCount
> 1), isLanguage (Lang_csharp
));
2715 exception
= (exception_t
) setjmp (Exception
);
2718 if (exception
== ExceptionNone
)
2720 createTags (0, NULL
);
2724 deleteAllStatements ();
2725 if (exception
== ExceptionBraceFormattingError
&& passCount
== 1)
2728 verbose ("%s: retrying file with fallback brace matching algorithm\n",
2729 getInputFileName ());
2736 static void buildKeywordHash (const langType language
, unsigned int idx
)
2738 const size_t count
= sizeof (KeywordTable
) / sizeof (KeywordTable
[0]);
2740 for (i
= 0 ; i
< count
; ++i
)
2742 const keywordDesc
* const p
= &KeywordTable
[i
];
2743 if (p
->isValid
[idx
])
2744 addKeyword (p
->name
, language
, (int) p
->id
);
2748 static void initializeCParser (const langType language
)
2750 contextual_fake_count
= 0;
2752 buildKeywordHash (language
, 0);
2755 static void initializeCppParser (const langType language
)
2757 contextual_fake_count
= 0;
2758 Lang_cpp
= language
;
2759 buildKeywordHash (language
, 1);
2762 static void initializeJavaParser (const langType language
)
2764 contextual_fake_count
= 0;
2765 Lang_java
= language
;
2766 buildKeywordHash (language
, 3);
2769 static void initializeDParser (const langType language
)
2771 contextual_fake_count
= 0;
2773 buildKeywordHash (language
, 1); /* C++ keywords */
2776 static void initializeGLSLParser (const langType language
)
2778 contextual_fake_count
= 0;
2779 Lang_glsl
= language
;
2780 buildKeywordHash (language
, 0);
2783 static void initializeFeriteParser (const langType language
)
2785 contextual_fake_count
= 0;
2786 Lang_ferite
= language
;
2787 buildKeywordHash (language
, 1); /* C++ keywords */
2790 static void initializeCsharpParser (const langType language
)
2792 contextual_fake_count
= 0;
2793 Lang_csharp
= language
;
2794 buildKeywordHash (language
, 2);
2797 extern parserDefinition
* CParser (void)
2799 static const char *const extensions
[] = { "c", "pc", "sc", NULL
};
2800 parserDefinition
* def
= parserNew ("C");
2801 def
->kinds
= CKinds
;
2802 def
->kindCount
= KIND_COUNT (CKinds
);
2803 def
->extensions
= extensions
;
2804 def
->parser2
= findCTags
;
2805 def
->initialize
= initializeCParser
;
2809 extern parserDefinition
* CppParser (void)
2811 static const char *const extensions
[] = {
2812 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
2814 #ifndef CASE_INSENSITIVE_FILENAMES
2819 parserDefinition
* def
= parserNew ("C++");
2820 def
->kinds
= CKinds
;
2821 def
->kindCount
= KIND_COUNT (CKinds
);
2822 def
->extensions
= extensions
;
2823 def
->parser2
= findCTags
;
2824 def
->initialize
= initializeCppParser
;
2828 extern parserDefinition
* JavaParser (void)
2830 static const char *const extensions
[] = { "java", NULL
};
2831 parserDefinition
* def
= parserNew ("Java");
2832 def
->kinds
= JavaKinds
;
2833 def
->kindCount
= KIND_COUNT (JavaKinds
);
2834 def
->extensions
= extensions
;
2835 def
->parser2
= findCTags
;
2836 def
->initialize
= initializeJavaParser
;
2840 extern parserDefinition
* DParser (void)
2842 static const char *const extensions
[] = { "d", "di", NULL
};
2843 parserDefinition
* def
= parserNew ("D");
2844 def
->kinds
= CKinds
;
2845 def
->kindCount
= KIND_COUNT (CKinds
);
2846 def
->extensions
= extensions
;
2847 def
->parser2
= findCTags
;
2848 def
->initialize
= initializeDParser
;
2852 extern parserDefinition
* GLSLParser (void)
2854 static const char *const extensions
[] = { "glsl", "frag", "vert", NULL
};
2855 parserDefinition
* def
= parserNew ("GLSL");
2856 def
->kinds
= CKinds
;
2857 def
->kindCount
= KIND_COUNT (CKinds
);
2858 def
->extensions
= extensions
;
2859 def
->parser2
= findCTags
;
2860 def
->initialize
= initializeGLSLParser
;
2864 extern parserDefinition
* FeriteParser (void)
2866 static const char *const extensions
[] = { "fe", NULL
};
2867 parserDefinition
* def
= parserNew ("Ferite");
2868 def
->kinds
= CKinds
;
2869 def
->kindCount
= KIND_COUNT (CKinds
);
2870 def
->extensions
= extensions
;
2871 def
->parser2
= findCTags
;
2872 def
->initialize
= initializeFeriteParser
;
2876 extern parserDefinition
* CsharpParser (void)
2878 static const char *const extensions
[] = { "cs", NULL
};
2879 parserDefinition
* def
= parserNew ("C#");
2880 def
->kinds
= CsharpKinds
;
2881 def
->kindCount
= KIND_COUNT (CsharpKinds
);
2882 def
->extensions
= extensions
;
2883 def
->parser2
= findCTags
;
2884 def
->initialize
= initializeCsharpParser
;
2887 /* vi:set tabstop=8 shiftwidth=4: */