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