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 */
35 #define stringValue(a) #a
36 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
37 #define parentDecl(st) ((st)->parent == NULL ? \
38 DECL_NONE : (st)->parent->declaration)
39 #define isType(token,t) (boolean) ((token)->type == (t))
40 #define insideEnumBody(st) ((st)->parent == NULL ? FALSE : \
41 (boolean) ((st)->parent->declaration == DECL_ENUM))
42 #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
43 ! (st)->haveQualifyingName && (st)->scope == SCOPE_EXTERN)
45 #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
47 #define isHighChar(c) ((c) != EOF && (unsigned char)(c) >= 0xc0)
53 enum { NumTokens
= 3 };
55 typedef enum eException
{
56 ExceptionNone
, ExceptionEOF
, ExceptionFormattingError
,
57 ExceptionBraceFormattingError
60 /* Used to specify type of keyword.
62 typedef enum eKeywordId
{
64 KEYWORD_ATTRIBUTE
, KEYWORD_ABSTRACT
,
65 KEYWORD_BOOLEAN
, KEYWORD_BYTE
, KEYWORD_BAD_STATE
, KEYWORD_BAD_TRANS
,
66 KEYWORD_BIND
, KEYWORD_BIND_VAR
, KEYWORD_BIT
,
67 KEYWORD_CASE
, KEYWORD_CATCH
, KEYWORD_CHAR
, KEYWORD_CLASS
, KEYWORD_CONST
,
68 KEYWORD_CONSTRAINT
, KEYWORD_COVERAGE_BLOCK
, KEYWORD_COVERAGE_DEF
,
69 KEYWORD_DEFAULT
, KEYWORD_DELEGATE
, KEYWORD_DELETE
, KEYWORD_DO
,
71 KEYWORD_ELSE
, KEYWORD_ENUM
, KEYWORD_EXPLICIT
, KEYWORD_EXTERN
,
72 KEYWORD_EXTENDS
, KEYWORD_EVENT
,
73 KEYWORD_FINAL
, KEYWORD_FLOAT
, KEYWORD_FOR
, KEYWORD_FRIEND
, KEYWORD_FUNCTION
,
75 KEYWORD_IF
, KEYWORD_IMPLEMENTS
, KEYWORD_IMPORT
, KEYWORD_INLINE
, KEYWORD_INT
,
76 KEYWORD_INOUT
, KEYWORD_INPUT
, KEYWORD_INTEGER
, KEYWORD_INTERFACE
,
78 KEYWORD_LOCAL
, KEYWORD_LONG
,
79 KEYWORD_M_BAD_STATE
, KEYWORD_M_BAD_TRANS
, KEYWORD_M_STATE
, KEYWORD_M_TRANS
,
81 KEYWORD_NAMESPACE
, KEYWORD_NEW
, KEYWORD_NEWCOV
, KEYWORD_NATIVE
,
82 KEYWORD_OPERATOR
, KEYWORD_OUTPUT
, KEYWORD_OVERLOAD
, KEYWORD_OVERRIDE
,
83 KEYWORD_PACKED
, KEYWORD_PORT
, KEYWORD_PACKAGE
, KEYWORD_PRIVATE
,
84 KEYWORD_PROGRAM
, KEYWORD_PROTECTED
, KEYWORD_PUBLIC
,
85 KEYWORD_REGISTER
, KEYWORD_RETURN
,
86 KEYWORD_SHADOW
, KEYWORD_STATE
,
87 KEYWORD_SHORT
, KEYWORD_SIGNED
, KEYWORD_STATIC
, KEYWORD_STRING
,
88 KEYWORD_STRUCT
, KEYWORD_SWITCH
, KEYWORD_SYNCHRONIZED
,
89 KEYWORD_TASK
, KEYWORD_TEMPLATE
, KEYWORD_THIS
, KEYWORD_THROW
,
90 KEYWORD_THROWS
, KEYWORD_TRANSIENT
, KEYWORD_TRANS
, KEYWORD_TRANSITION
,
91 KEYWORD_TRY
, KEYWORD_TYPEDEF
, KEYWORD_TYPENAME
,
92 KEYWORD_UINT
, KEYWORD_ULONG
, KEYWORD_UNION
, KEYWORD_UNSIGNED
, KEYWORD_USHORT
,
94 KEYWORD_VIRTUAL
, KEYWORD_VOID
, KEYWORD_VOLATILE
,
95 KEYWORD_WCHAR_T
, KEYWORD_WHILE
98 /* Used to determine whether keyword is valid for the current language and
101 typedef struct sKeywordDesc
{
104 short isValid
[5]; /* indicates languages for which kw is valid */
107 /* Used for reporting the type of object parsed by nextToken ().
109 typedef enum eTokenType
{
110 TOKEN_NONE
, /* none */
111 TOKEN_ARGS
, /* a parenthetical pair and its contents */
114 TOKEN_COLON
, /* the colon character */
115 TOKEN_COMMA
, /* the comma character */
116 TOKEN_DOUBLE_COLON
, /* double colon indicates nested-name-specifier */
118 TOKEN_NAME
, /* an unknown name */
119 TOKEN_PACKAGE
, /* a Java package name */
120 TOKEN_PAREN_NAME
, /* a single name in parentheses */
121 TOKEN_SEMICOLON
, /* the semicolon character */
122 TOKEN_SPEC
, /* a storage class specifier, qualifier, type, etc. */
126 /* This describes the scoping of the current statement.
128 typedef enum eTagScope
{
129 SCOPE_GLOBAL
, /* no storage class specified */
130 SCOPE_STATIC
, /* static storage class */
131 SCOPE_EXTERN
, /* external storage class */
132 SCOPE_FRIEND
, /* declares access only */
133 SCOPE_TYPEDEF
, /* scoping depends upon context */
137 typedef enum eDeclaration
{
139 DECL_BASE
, /* base type (default) */
144 DECL_IGNORE
, /* non-taggable "declaration" */
147 DECL_NOMANGLE
, /* C++ name demangling block */
149 DECL_PROGRAM
, /* Vera program */
151 DECL_TASK
, /* Vera task */
156 typedef enum eVisibilityType
{
162 ACCESS_DEFAULT
, /* Java-specific */
166 /* Information about the parent class of a member (if any).
168 typedef struct sMemberInfo
{
169 accessType access
; /* access of current statement */
170 accessType accessDefault
; /* access default for current statement */
173 typedef struct sTokenInfo
{
176 vString
* name
; /* the name of the token */
177 unsigned long lineNumber
; /* line number of tag */
178 fpos_t filePosition
; /* file position of line containing name */
181 typedef enum eImplementation
{
189 /* Describes the statement currently undergoing analysis.
191 typedef struct sStatementInfo
{
193 declType declaration
; /* specifier associated with TOKEN_SPEC */
194 boolean gotName
; /* was a name parsed yet? */
195 boolean haveQualifyingName
; /* do we have a name we are considering? */
196 boolean gotParenName
; /* was a name inside parentheses parsed yet? */
197 boolean gotArgs
; /* was a list of parameters parsed yet? */
198 boolean isPointer
; /* is 'name' a pointer? */
199 boolean inFunction
; /* are we inside of a function? */
200 boolean assignment
; /* have we handled an '='? */
201 boolean notVariable
; /* has a variable declaration been disqualified ? */
202 impType implementation
; /* abstract or concrete implementation? */
203 unsigned int tokenIndex
; /* currently active token */
204 tokenInfo
* token
[(int) NumTokens
];
205 tokenInfo
* context
; /* accumulated scope of current statement */
206 tokenInfo
* blockName
; /* name of current block */
207 memberInfo member
; /* information regarding parent class/struct */
208 vString
* parentClasses
; /* parent classes */
209 struct sStatementInfo
*parent
; /* statement we are nested within */
212 /* Describes the type of tag being generated.
214 typedef enum eTagType
{
216 TAG_CLASS
, /* class name */
217 TAG_ENUM
, /* enumeration name */
218 TAG_ENUMERATOR
, /* enumerator (enumeration value) */
219 TAG_EVENT
, /* event */
220 TAG_FIELD
, /* field (Java) */
221 TAG_FUNCTION
, /* function definition */
222 TAG_INTERFACE
, /* interface declaration */
223 TAG_LOCAL
, /* local variable definition */
224 TAG_MEMBER
, /* structure, class or interface member */
225 TAG_METHOD
, /* method declaration */
226 TAG_NAMESPACE
, /* namespace name */
227 TAG_PACKAGE
, /* package name */
228 TAG_PROGRAM
, /* program name */
229 TAG_PROPERTY
, /* property name */
230 TAG_PROTOTYPE
, /* function prototype or declaration */
231 TAG_STRUCT
, /* structure name */
232 TAG_TASK
, /* task name */
233 TAG_TYPEDEF
, /* typedef name */
234 TAG_UNION
, /* union name */
235 TAG_VARIABLE
, /* variable definition */
236 TAG_EXTERN_VAR
, /* external variable declaration */
237 TAG_COUNT
/* must be last */
240 typedef struct sParenInfo
{
243 boolean isKnrParamList
;
244 boolean isNameCandidate
;
245 boolean invalidContents
;
247 unsigned int parameterCount
;
254 static jmp_buf Exception
;
256 static langType Lang_c
;
257 static langType Lang_cpp
;
258 static langType Lang_csharp
;
259 static langType Lang_java
;
260 static langType Lang_vera
;
261 static vString
*Signature
;
262 static boolean CollectingSignature
;
264 /* Number used to uniquely identify anonymous structs and unions. */
265 static int AnonymousID
= 0;
267 /* Used to index into the CKinds table. */
270 CK_CLASS
, CK_DEFINE
, CK_ENUMERATOR
, CK_FUNCTION
,
271 CK_ENUMERATION
, CK_LOCAL
, CK_MEMBER
, CK_NAMESPACE
, CK_PROTOTYPE
,
272 CK_STRUCT
, CK_TYPEDEF
, CK_UNION
, CK_VARIABLE
,
276 static kindOption CKinds
[] = {
277 { TRUE
, 'c', "class", "classes"},
278 { TRUE
, 'd', "macro", "macro definitions"},
279 { TRUE
, 'e', "enumerator", "enumerators (values inside an enumeration)"},
280 { TRUE
, 'f', "function", "function definitions"},
281 { TRUE
, 'g', "enum", "enumeration names"},
282 { FALSE
, 'l', "local", "local variables"},
283 { TRUE
, 'm', "member", "class, struct, and union members"},
284 { TRUE
, 'n', "namespace", "namespaces"},
285 { TRUE
/*FALSE*/, 'p', "prototype", "function prototypes"},
286 { TRUE
, 's', "struct", "structure names"},
287 { TRUE
, 't', "typedef", "typedefs"},
288 { TRUE
, 'u', "union", "union names"},
289 { TRUE
, 'v', "variable", "variable definitions"},
290 { FALSE
, 'x', "externvar", "external variable declarations"},
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 /* Used to index into the JavaKinds table. */
319 JK_CLASS
, JK_FIELD
, JK_INTERFACE
, JK_LOCAL
, JK_METHOD
,
320 JK_PACKAGE
, JK_ACCESS
, JK_CLASS_PREFIX
323 static kindOption JavaKinds
[] = {
324 { TRUE
, 'c', "class", "classes"},
325 { TRUE
, 'f', "field", "fields"},
326 { TRUE
, 'i', "interface", "interfaces"},
327 { FALSE
, 'l', "local", "local variables"},
328 { TRUE
, 'm', "method", "methods"},
329 { TRUE
, 'p', "package", "packages"},
332 /* Used to index into the VeraKinds table. */
335 VK_CLASS
, VK_DEFINE
, VK_ENUMERATOR
, VK_FUNCTION
,
336 VK_ENUMERATION
, VK_LOCAL
, VK_MEMBER
, VK_PROGRAM
, VK_PROTOTYPE
,
337 VK_TASK
, VK_TYPEDEF
, VK_VARIABLE
,
341 static kindOption VeraKinds
[] = {
342 { TRUE
, 'c', "class", "classes"},
343 { TRUE
, 'd', "macro", "macro definitions"},
344 { TRUE
, 'e', "enumerator", "enumerators (values inside an enumeration)"},
345 { TRUE
, 'f', "function", "function definitions"},
346 { TRUE
, 'g', "enum", "enumeration names"},
347 { FALSE
, 'l', "local", "local variables"},
348 { TRUE
, 'm', "member", "class, struct, and union members"},
349 { TRUE
, 'p', "program", "programs"},
350 { FALSE
, 'P', "prototype", "function prototypes"},
351 { TRUE
, 't', "task", "tasks"},
352 { TRUE
, 'T', "typedef", "typedefs"},
353 { TRUE
, 'v', "variable", "variable definitions"},
354 { FALSE
, 'x', "externvar", "external variable declarations"}
357 static const keywordDesc KeywordTable
[] = {
359 /* ANSI C | C# Java */
361 /* keyword keyword ID | | | | | */
362 { "__attribute__", KEYWORD_ATTRIBUTE
, { 1, 1, 1, 0, 0 } },
363 { "abstract", KEYWORD_ABSTRACT
, { 0, 0, 1, 1, 0 } },
364 { "bad_state", KEYWORD_BAD_STATE
, { 0, 0, 0, 0, 1 } },
365 { "bad_trans", KEYWORD_BAD_TRANS
, { 0, 0, 0, 0, 1 } },
366 { "bind", KEYWORD_BIND
, { 0, 0, 0, 0, 1 } },
367 { "bind_var", KEYWORD_BIND_VAR
, { 0, 0, 0, 0, 1 } },
368 { "bit", KEYWORD_BIT
, { 0, 0, 0, 0, 1 } },
369 { "boolean", KEYWORD_BOOLEAN
, { 0, 0, 0, 1, 0 } },
370 { "byte", KEYWORD_BYTE
, { 0, 0, 0, 1, 0 } },
371 { "case", KEYWORD_CASE
, { 1, 1, 1, 1, 0 } },
372 { "catch", KEYWORD_CATCH
, { 0, 1, 1, 0, 0 } },
373 { "char", KEYWORD_CHAR
, { 1, 1, 1, 1, 0 } },
374 { "class", KEYWORD_CLASS
, { 0, 1, 1, 1, 1 } },
375 { "const", KEYWORD_CONST
, { 1, 1, 1, 1, 0 } },
376 { "constraint", KEYWORD_CONSTRAINT
, { 0, 0, 0, 0, 1 } },
377 { "coverage_block", KEYWORD_COVERAGE_BLOCK
, { 0, 0, 0, 0, 1 } },
378 { "coverage_def", KEYWORD_COVERAGE_DEF
, { 0, 0, 0, 0, 1 } },
379 { "do", KEYWORD_DO
, { 1, 1, 1, 1, 0 } },
380 { "default", KEYWORD_DEFAULT
, { 1, 1, 1, 1, 0 } },
381 { "delegate", KEYWORD_DELEGATE
, { 0, 0, 1, 0, 0 } },
382 { "delete", KEYWORD_DELETE
, { 0, 1, 0, 0, 0 } },
383 { "double", KEYWORD_DOUBLE
, { 1, 1, 1, 1, 0 } },
384 { "else", KEYWORD_ELSE
, { 1, 1, 0, 1, 0 } },
385 { "enum", KEYWORD_ENUM
, { 1, 1, 1, 0, 1 } },
386 { "event", KEYWORD_EVENT
, { 0, 0, 1, 0, 1 } },
387 { "explicit", KEYWORD_EXPLICIT
, { 0, 1, 1, 0, 0 } },
388 { "extends", KEYWORD_EXTENDS
, { 0, 0, 0, 1, 1 } },
389 { "extern", KEYWORD_EXTERN
, { 1, 1, 1, 0, 1 } },
390 { "final", KEYWORD_FINAL
, { 0, 0, 0, 1, 0 } },
391 { "float", KEYWORD_FLOAT
, { 1, 1, 1, 1, 0 } },
392 { "for", KEYWORD_FOR
, { 1, 1, 1, 1, 0 } },
393 { "friend", KEYWORD_FRIEND
, { 0, 1, 0, 0, 0 } },
394 { "function", KEYWORD_FUNCTION
, { 0, 0, 0, 0, 1 } },
395 { "goto", KEYWORD_GOTO
, { 1, 1, 1, 1, 0 } },
396 { "if", KEYWORD_IF
, { 1, 1, 1, 1, 0 } },
397 { "implements", KEYWORD_IMPLEMENTS
, { 0, 0, 0, 1, 0 } },
398 { "import", KEYWORD_IMPORT
, { 0, 0, 0, 1, 0 } },
399 { "inline", KEYWORD_INLINE
, { 0, 1, 0, 0, 0 } },
400 { "inout", KEYWORD_INOUT
, { 0, 0, 0, 0, 1 } },
401 { "input", KEYWORD_INPUT
, { 0, 0, 0, 0, 1 } },
402 { "int", KEYWORD_INT
, { 1, 1, 1, 1, 0 } },
403 { "integer", KEYWORD_INTEGER
, { 0, 0, 0, 0, 1 } },
404 { "interface", KEYWORD_INTERFACE
, { 0, 0, 1, 1, 1 } },
405 { "internal", KEYWORD_INTERNAL
, { 0, 0, 1, 0, 0 } },
406 { "local", KEYWORD_LOCAL
, { 0, 0, 0, 0, 1 } },
407 { "long", KEYWORD_LONG
, { 1, 1, 1, 1, 0 } },
408 { "m_bad_state", KEYWORD_M_BAD_STATE
, { 0, 0, 0, 0, 1 } },
409 { "m_bad_trans", KEYWORD_M_BAD_TRANS
, { 0, 0, 0, 0, 1 } },
410 { "m_state", KEYWORD_M_STATE
, { 0, 0, 0, 0, 1 } },
411 { "m_trans", KEYWORD_M_TRANS
, { 0, 0, 0, 0, 1 } },
412 { "mutable", KEYWORD_MUTABLE
, { 0, 1, 0, 0, 0 } },
413 { "namespace", KEYWORD_NAMESPACE
, { 0, 1, 1, 0, 0 } },
414 { "native", KEYWORD_NATIVE
, { 0, 0, 0, 1, 0 } },
415 { "new", KEYWORD_NEW
, { 0, 1, 1, 1, 0 } },
416 { "newcov", KEYWORD_NEWCOV
, { 0, 0, 0, 0, 1 } },
417 { "operator", KEYWORD_OPERATOR
, { 0, 1, 1, 0, 0 } },
418 { "output", KEYWORD_OUTPUT
, { 0, 0, 0, 0, 1 } },
419 { "overload", KEYWORD_OVERLOAD
, { 0, 1, 0, 0, 0 } },
420 { "override", KEYWORD_OVERRIDE
, { 0, 0, 1, 0, 0 } },
421 { "package", KEYWORD_PACKAGE
, { 0, 0, 0, 1, 0 } },
422 { "packed", KEYWORD_PACKED
, { 0, 0, 0, 0, 1 } },
423 { "port", KEYWORD_PORT
, { 0, 0, 0, 0, 1 } },
424 { "private", KEYWORD_PRIVATE
, { 0, 1, 1, 1, 0 } },
425 { "program", KEYWORD_PROGRAM
, { 0, 0, 0, 0, 1 } },
426 { "protected", KEYWORD_PROTECTED
, { 0, 1, 1, 1, 1 } },
427 { "public", KEYWORD_PUBLIC
, { 0, 1, 1, 1, 1 } },
428 { "register", KEYWORD_REGISTER
, { 1, 1, 0, 0, 0 } },
429 { "return", KEYWORD_RETURN
, { 1, 1, 1, 1, 0 } },
430 { "shadow", KEYWORD_SHADOW
, { 0, 0, 0, 0, 1 } },
431 { "short", KEYWORD_SHORT
, { 1, 1, 1, 1, 0 } },
432 { "signed", KEYWORD_SIGNED
, { 1, 1, 0, 0, 0 } },
433 { "state", KEYWORD_STATE
, { 0, 0, 0, 0, 1 } },
434 { "static", KEYWORD_STATIC
, { 1, 1, 1, 1, 1 } },
435 { "string", KEYWORD_STRING
, { 0, 0, 1, 0, 1 } },
436 { "struct", KEYWORD_STRUCT
, { 1, 1, 1, 0, 0 } },
437 { "switch", KEYWORD_SWITCH
, { 1, 1, 1, 1, 0 } },
438 { "synchronized", KEYWORD_SYNCHRONIZED
, { 0, 0, 0, 1, 0 } },
439 { "task", KEYWORD_TASK
, { 0, 0, 0, 0, 1 } },
440 { "template", KEYWORD_TEMPLATE
, { 0, 1, 0, 0, 0 } },
441 { "this", KEYWORD_THIS
, { 0, 1, 1, 1, 0 } },
442 { "throw", KEYWORD_THROW
, { 0, 1, 1, 1, 0 } },
443 { "throws", KEYWORD_THROWS
, { 0, 0, 0, 1, 0 } },
444 { "trans", KEYWORD_TRANS
, { 0, 0, 0, 0, 1 } },
445 { "transition", KEYWORD_TRANSITION
, { 0, 0, 0, 0, 1 } },
446 { "transient", KEYWORD_TRANSIENT
, { 0, 0, 0, 1, 0 } },
447 { "try", KEYWORD_TRY
, { 0, 1, 1, 0, 0 } },
448 { "typedef", KEYWORD_TYPEDEF
, { 1, 1, 1, 0, 1 } },
449 { "typename", KEYWORD_TYPENAME
, { 0, 1, 0, 0, 0 } },
450 { "uint", KEYWORD_UINT
, { 0, 0, 1, 0, 0 } },
451 { "ulong", KEYWORD_ULONG
, { 0, 0, 1, 0, 0 } },
452 { "union", KEYWORD_UNION
, { 1, 1, 0, 0, 0 } },
453 { "unsigned", KEYWORD_UNSIGNED
, { 1, 1, 1, 0, 0 } },
454 { "ushort", KEYWORD_USHORT
, { 0, 0, 1, 0, 0 } },
455 { "using", KEYWORD_USING
, { 0, 1, 1, 0, 0 } },
456 { "virtual", KEYWORD_VIRTUAL
, { 0, 1, 1, 0, 1 } },
457 { "void", KEYWORD_VOID
, { 1, 1, 1, 1, 1 } },
458 { "volatile", KEYWORD_VOLATILE
, { 1, 1, 1, 1, 0 } },
459 { "wchar_t", KEYWORD_WCHAR_T
, { 1, 1, 1, 0, 0 } },
460 { "while", KEYWORD_WHILE
, { 1, 1, 1, 1, 0 } }
464 * FUNCTION PROTOTYPES
466 static void createTags (const unsigned int nestLevel
, statementInfo
*const parent
);
469 * FUNCTION DEFINITIONS
472 extern boolean
includingDefineTags (void)
474 return CKinds
[CK_DEFINE
].enabled
;
481 static void initToken (tokenInfo
* const token
)
483 token
->type
= TOKEN_NONE
;
484 token
->keyword
= KEYWORD_NONE
;
485 token
->lineNumber
= getSourceLineNumber ();
486 token
->filePosition
= getInputFilePosition ();
487 vStringClear (token
->name
);
490 static void advanceToken (statementInfo
* const st
)
492 if (st
->tokenIndex
>= (unsigned int) NumTokens
- 1)
496 initToken (st
->token
[st
->tokenIndex
]);
499 static tokenInfo
*prevToken (const statementInfo
*const st
, unsigned int n
)
501 unsigned int tokenIndex
;
502 unsigned int num
= (unsigned int) NumTokens
;
504 tokenIndex
= (st
->tokenIndex
+ num
- n
) % num
;
505 return st
->token
[tokenIndex
];
508 static void setToken (statementInfo
*const st
, const tokenType type
)
511 token
= activeToken (st
);
516 static void retardToken (statementInfo
*const st
)
518 if (st
->tokenIndex
== 0)
519 st
->tokenIndex
= (unsigned int) NumTokens
- 1;
522 setToken (st
, TOKEN_NONE
);
525 static tokenInfo
*newToken (void)
527 tokenInfo
*const token
= xMalloc (1, tokenInfo
);
528 token
->name
= vStringNew ();
533 static void deleteToken (tokenInfo
*const token
)
537 vStringDelete (token
->name
);
542 static const char *accessString (const accessType access
)
544 static const char *const names
[] = {
545 "?", "local", "private", "protected", "public", "default"
547 Assert (sizeof (names
) / sizeof (names
[0]) == ACCESS_COUNT
);
548 Assert ((int) access
< ACCESS_COUNT
);
549 return names
[(int) access
];
552 static const char *implementationString (const impType imp
)
554 static const char *const names
[] ={
555 "?", "abstract", "virtual", "pure virtual"
557 Assert (sizeof (names
) / sizeof (names
[0]) == IMP_COUNT
);
558 Assert ((int) imp
< IMP_COUNT
);
559 return names
[(int) imp
];
563 * Debugging functions
568 #define boolString(c) ((c) ? "TRUE" : "FALSE")
570 static const char *tokenString (const tokenType type
)
572 static const char *const names
[] = {
573 "none", "args", "}", "{", "colon", "comma", "double colon", "keyword",
574 "name", "package", "paren-name", "semicolon", "specifier"
576 Assert (sizeof (names
) / sizeof (names
[0]) == TOKEN_COUNT
);
577 Assert ((int) type
< TOKEN_COUNT
);
578 return names
[(int) type
];
581 static const char *scopeString (const tagScope scope
)
583 static const char *const names
[] = {
584 "global", "static", "extern", "friend", "typedef"
586 Assert (sizeof (names
) / sizeof (names
[0]) == SCOPE_COUNT
);
587 Assert ((int) scope
< SCOPE_COUNT
);
588 return names
[(int) scope
];
591 static const char *declString (const declType declaration
)
593 static const char *const names
[] = {
594 "?", "base", "class", "enum", "event", "function", "ignore",
595 "interface", "namespace", "no mangle", "package", "program",
596 "struct", "task", "union",
598 Assert (sizeof (names
) / sizeof (names
[0]) == DECL_COUNT
);
599 Assert ((int) declaration
< DECL_COUNT
);
600 return names
[(int) declaration
];
603 static const char *keywordString (const keywordId keyword
)
605 const size_t count
= sizeof (KeywordTable
) / sizeof (KeywordTable
[0]);
606 const char *name
= "none";
608 for (i
= 0 ; i
< count
; ++i
)
610 const keywordDesc
*p
= &KeywordTable
[i
];
611 if (p
->id
== keyword
)
620 static void __unused__
pt (tokenInfo
*const token
)
622 if (isType (token
, TOKEN_NAME
))
623 printf ("type: %-12s: %-13s line: %lu\n",
624 tokenString (token
->type
), vStringValue (token
->name
),
626 else if (isType (token
, TOKEN_KEYWORD
))
627 printf ("type: %-12s: %-13s line: %lu\n",
628 tokenString (token
->type
), keywordString (token
->keyword
),
631 printf ("type: %-12s line: %lu\n",
632 tokenString (token
->type
), token
->lineNumber
);
635 static void __unused__
ps (statementInfo
*const st
)
638 printf ("scope: %s decl: %s gotName: %s gotParenName: %s\n",
639 scopeString (st
->scope
), declString (st
->declaration
),
640 boolString (st
->gotName
), boolString (st
->gotParenName
));
641 printf ("haveQualifyingName: %s\n", boolString (st
->haveQualifyingName
));
642 printf ("access: %s default: %s\n", accessString (st
->member
.access
),
643 accessString (st
->member
.accessDefault
));
645 pt (activeToken (st
));
646 for (i
= 1 ; i
< (unsigned int) NumTokens
; ++i
)
648 printf ("prev %u : ", i
);
649 pt (prevToken (st
, i
));
651 printf ("context: ");
658 * Statement management
661 static boolean
isContextualKeyword (const tokenInfo
*const token
)
664 switch (token
->keyword
)
668 case KEYWORD_INTERFACE
:
669 case KEYWORD_NAMESPACE
:
675 default: result
= FALSE
; break;
680 static boolean
isContextualStatement (const statementInfo
*const st
)
682 boolean result
= FALSE
;
683 if (st
!= NULL
) switch (st
->declaration
)
693 default: result
= FALSE
; break;
698 static boolean
isMember (const statementInfo
*const st
)
701 if (isType (st
->context
, TOKEN_NAME
))
705 (st
->parent
!= NULL
&& isContextualStatement (st
->parent
));
709 static void initMemberInfo (statementInfo
*const st
)
711 accessType accessDefault
= ACCESS_UNDEFINED
;
713 if (st
->parent
!= NULL
) switch (st
->parent
->declaration
)
718 accessDefault
= ACCESS_UNDEFINED
;
722 if (isLanguage (Lang_java
))
723 accessDefault
= ACCESS_DEFAULT
;
725 accessDefault
= ACCESS_PRIVATE
;
730 accessDefault
= ACCESS_PUBLIC
;
735 st
->member
.accessDefault
= accessDefault
;
736 st
->member
.access
= accessDefault
;
739 static void reinitStatement (statementInfo
*const st
, const boolean partial
)
745 st
->scope
= SCOPE_GLOBAL
;
746 if (isContextualStatement (st
->parent
))
747 st
->declaration
= DECL_BASE
;
749 st
->declaration
= DECL_NONE
;
751 st
->gotParenName
= FALSE
;
752 st
->isPointer
= FALSE
;
753 st
->inFunction
= FALSE
;
754 st
->assignment
= FALSE
;
755 st
->notVariable
= FALSE
;
756 st
->implementation
= IMP_DEFAULT
;
759 st
->haveQualifyingName
= FALSE
;
762 if (st
->parent
!= NULL
)
763 st
->inFunction
= st
->parent
->inFunction
;
765 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
766 initToken (st
->token
[i
]);
768 initToken (st
->context
);
770 /* Keep the block name, so that a variable following after a comma will
771 * still have the structure name.
774 initToken (st
->blockName
);
776 vStringClear (st
->parentClasses
);
781 st
->member
.access
= st
->member
.accessDefault
;
784 static void initStatement (statementInfo
*const st
, statementInfo
*const parent
)
788 reinitStatement (st
, FALSE
);
792 * Tag generation functions
794 static cKind
cTagKind (const tagType type
)
796 cKind result
= CK_UNDEFINED
;
799 case TAG_CLASS
: result
= CK_CLASS
; break;
800 case TAG_ENUM
: result
= CK_ENUMERATION
; break;
801 case TAG_ENUMERATOR
: result
= CK_ENUMERATOR
; break;
802 case TAG_FUNCTION
: result
= CK_FUNCTION
; break;
803 case TAG_LOCAL
: result
= CK_LOCAL
; break;
804 case TAG_MEMBER
: result
= CK_MEMBER
; break;
805 case TAG_NAMESPACE
: result
= CK_NAMESPACE
; break;
806 case TAG_PROTOTYPE
: result
= CK_PROTOTYPE
; break;
807 case TAG_STRUCT
: result
= CK_STRUCT
; break;
808 case TAG_TYPEDEF
: result
= CK_TYPEDEF
; break;
809 case TAG_UNION
: result
= CK_UNION
; break;
810 case TAG_VARIABLE
: result
= CK_VARIABLE
; break;
811 case TAG_EXTERN_VAR
: result
= CK_EXTERN_VARIABLE
; break;
813 default: Assert ("Bad C tag type" == NULL
); break;
818 static csharpKind
csharpTagKind (const tagType type
)
820 csharpKind result
= CSK_UNDEFINED
;
823 case TAG_CLASS
: result
= CSK_CLASS
; break;
824 case TAG_ENUM
: result
= CSK_ENUMERATION
; break;
825 case TAG_ENUMERATOR
: result
= CSK_ENUMERATOR
; break;
826 case TAG_EVENT
: result
= CSK_EVENT
; break;
827 case TAG_FIELD
: result
= CSK_FIELD
; break;
828 case TAG_INTERFACE
: result
= CSK_INTERFACE
; break;
829 case TAG_LOCAL
: result
= CSK_LOCAL
; break;
830 case TAG_METHOD
: result
= CSK_METHOD
; break;
831 case TAG_NAMESPACE
: result
= CSK_NAMESPACE
; break;
832 case TAG_PROPERTY
: result
= CSK_PROPERTY
; break;
833 case TAG_STRUCT
: result
= CSK_STRUCT
; break;
834 case TAG_TYPEDEF
: result
= CSK_TYPEDEF
; break;
836 default: Assert ("Bad C# tag type" == NULL
); break;
841 static javaKind
javaTagKind (const tagType type
)
843 javaKind result
= JK_UNDEFINED
;
846 case TAG_CLASS
: result
= JK_CLASS
; break;
847 case TAG_FIELD
: result
= JK_FIELD
; break;
848 case TAG_INTERFACE
: result
= JK_INTERFACE
; break;
849 case TAG_LOCAL
: result
= JK_LOCAL
; break;
850 case TAG_METHOD
: result
= JK_METHOD
; break;
851 case TAG_PACKAGE
: result
= JK_PACKAGE
; break;
853 default: Assert ("Bad Java tag type" == NULL
); break;
858 static veraKind
veraTagKind (const tagType type
) {
859 veraKind result
= VK_UNDEFINED
;
862 case TAG_CLASS
: result
= VK_CLASS
; break;
863 case TAG_ENUM
: result
= VK_ENUMERATION
; break;
864 case TAG_ENUMERATOR
: result
= VK_ENUMERATOR
; break;
865 case TAG_FUNCTION
: result
= VK_FUNCTION
; break;
866 case TAG_LOCAL
: result
= VK_LOCAL
; break;
867 case TAG_MEMBER
: result
= VK_MEMBER
; break;
868 case TAG_PROGRAM
: result
= VK_PROGRAM
; break;
869 case TAG_PROTOTYPE
: result
= VK_PROTOTYPE
; break;
870 case TAG_TASK
: result
= VK_TASK
; break;
871 case TAG_TYPEDEF
: result
= VK_TYPEDEF
; break;
872 case TAG_VARIABLE
: result
= VK_VARIABLE
; break;
873 case TAG_EXTERN_VAR
: result
= VK_EXTERN_VARIABLE
; break;
875 default: Assert ("Bad Vera tag type" == NULL
); break;
880 static const char *tagName (const tagType type
)
883 if (isLanguage (Lang_csharp
))
884 result
= CsharpKinds
[csharpTagKind (type
)].name
;
885 else if (isLanguage (Lang_java
))
886 result
= JavaKinds
[javaTagKind (type
)].name
;
887 else if (isLanguage (Lang_vera
))
888 result
= VeraKinds
[veraTagKind (type
)].name
;
890 result
= CKinds
[cTagKind (type
)].name
;
894 static int tagLetter (const tagType type
)
897 if (isLanguage (Lang_csharp
))
898 result
= CsharpKinds
[csharpTagKind (type
)].letter
;
899 else if (isLanguage (Lang_java
))
900 result
= JavaKinds
[javaTagKind (type
)].letter
;
901 else if (isLanguage (Lang_vera
))
902 result
= VeraKinds
[veraTagKind (type
)].letter
;
904 result
= CKinds
[cTagKind (type
)].letter
;
908 static boolean
includeTag (const tagType type
, const boolean isFileScope
)
911 if (isFileScope
&& ! Option
.include
.fileScope
)
913 else if (isLanguage (Lang_csharp
))
914 result
= CsharpKinds
[csharpTagKind (type
)].enabled
;
915 else if (isLanguage (Lang_java
))
916 result
= JavaKinds
[javaTagKind (type
)].enabled
;
917 else if (isLanguage (Lang_vera
))
918 result
= VeraKinds
[veraTagKind (type
)].enabled
;
920 result
= CKinds
[cTagKind (type
)].enabled
;
924 static tagType
declToTagType (const declType declaration
)
926 tagType type
= TAG_UNDEFINED
;
930 case DECL_CLASS
: type
= TAG_CLASS
; break;
931 case DECL_ENUM
: type
= TAG_ENUM
; break;
932 case DECL_EVENT
: type
= TAG_EVENT
; break;
933 case DECL_FUNCTION
: type
= TAG_FUNCTION
; break;
934 case DECL_INTERFACE
: type
= TAG_INTERFACE
; break;
935 case DECL_NAMESPACE
: type
= TAG_NAMESPACE
; break;
936 case DECL_PROGRAM
: type
= TAG_PROGRAM
; break;
937 case DECL_TASK
: type
= TAG_TASK
; break;
938 case DECL_STRUCT
: type
= TAG_STRUCT
; break;
939 case DECL_UNION
: type
= TAG_UNION
; break;
941 default: Assert ("Unexpected declaration" == NULL
); break;
946 static const char* accessField (const statementInfo
*const st
)
948 const char* result
= NULL
;
949 if (isLanguage (Lang_cpp
) && st
->scope
== SCOPE_FRIEND
)
951 else if (st
->member
.access
!= ACCESS_UNDEFINED
)
952 result
= accessString (st
->member
.access
);
956 static void addContextSeparator (vString
*const scope
)
958 if (isLanguage (Lang_c
) || isLanguage (Lang_cpp
))
959 vStringCatS (scope
, "::");
960 else if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
))
961 vStringCatS (scope
, ".");
964 static void addOtherFields (tagEntryInfo
* const tag
, const tagType type
,
965 const statementInfo
*const st
,
966 vString
*const scope
, vString
*const typeRef
)
968 /* For selected tag types, append an extension flag designating the
969 * parent object in which the tag is defined.
978 if (vStringLength (Signature
) > 0)
979 tag
->extensionFields
.signature
= vStringValue (Signature
);
993 if (vStringLength (scope
) > 0 &&
994 (isMember (st
) || st
->parent
->declaration
== DECL_NAMESPACE
))
996 if (isType (st
->context
, TOKEN_NAME
))
997 tag
->extensionFields
.scope
[0] = tagName (TAG_CLASS
);
999 tag
->extensionFields
.scope
[0] =
1000 tagName (declToTagType (parentDecl (st
)));
1001 tag
->extensionFields
.scope
[1] = vStringValue (scope
);
1003 if ((type
== TAG_CLASS
|| type
== TAG_INTERFACE
||
1004 type
== TAG_STRUCT
) && vStringLength (st
->parentClasses
) > 0)
1007 tag
->extensionFields
.inheritance
=
1008 vStringValue (st
->parentClasses
);
1010 if (st
->implementation
!= IMP_DEFAULT
&&
1011 (isLanguage (Lang_cpp
) || isLanguage (Lang_csharp
) ||
1012 isLanguage (Lang_java
)))
1014 tag
->extensionFields
.implementation
=
1015 implementationString (st
->implementation
);
1019 tag
->extensionFields
.access
= accessField (st
);
1024 /* Add typename info, type of the tag and name of struct/union/etc. */
1025 if ((type
== TAG_TYPEDEF
|| type
== TAG_VARIABLE
|| type
== TAG_MEMBER
)
1026 && isContextualStatement(st
))
1030 tag
->extensionFields
.typeRef
[0] =
1031 tagName (declToTagType (st
->declaration
));
1032 p
= vStringValue (st
->blockName
->name
);
1034 /* If there was no {} block get the name from the token before the
1035 * name (current token is ';' or ',', previous token is the name).
1037 if (p
== NULL
|| *p
== '\0')
1039 tokenInfo
*const prev2
= prevToken (st
, 2);
1040 if (isType (prev2
, TOKEN_NAME
))
1041 p
= vStringValue (prev2
->name
);
1044 /* Prepend the scope name if there is one. */
1045 if (vStringLength (scope
) > 0)
1047 vStringCopy(typeRef
, scope
);
1048 addContextSeparator (typeRef
);
1049 vStringCatS(typeRef
, p
);
1050 p
= vStringValue (typeRef
);
1052 tag
->extensionFields
.typeRef
[1] = p
;
1056 static void findScopeHierarchy (vString
*const string
,
1057 const statementInfo
*const st
)
1059 vStringClear (string
);
1060 if (isType (st
->context
, TOKEN_NAME
))
1061 vStringCopy (string
, st
->context
->name
);
1062 if (st
->parent
!= NULL
)
1064 vString
*temp
= vStringNew ();
1065 const statementInfo
*s
;
1066 for (s
= st
->parent
; s
!= NULL
; s
= s
->parent
)
1068 if (isContextualStatement (s
) ||
1069 s
->declaration
== DECL_NAMESPACE
||
1070 s
->declaration
== DECL_PROGRAM
)
1072 vStringCopy (temp
, string
);
1073 vStringClear (string
);
1074 Assert (isType (s
->blockName
, TOKEN_NAME
));
1075 if (isType (s
->context
, TOKEN_NAME
) &&
1076 vStringLength (s
->context
->name
) > 0)
1078 vStringCat (string
, s
->context
->name
);
1079 addContextSeparator (string
);
1081 vStringCat (string
, s
->blockName
->name
);
1082 if (vStringLength (temp
) > 0)
1083 addContextSeparator (string
);
1084 vStringCat (string
, temp
);
1087 vStringDelete (temp
);
1091 static void makeExtraTagEntry (const tagType type
, tagEntryInfo
*const e
,
1092 vString
*const scope
)
1094 if (Option
.include
.qualifiedTags
&&
1095 scope
!= NULL
&& vStringLength (scope
) > 0)
1097 vString
*const scopedName
= vStringNew ();
1099 if (type
!= TAG_ENUMERATOR
)
1100 vStringCopy (scopedName
, scope
);
1103 /* remove last component (i.e. enumeration name) from scope */
1104 const char* const sc
= vStringValue (scope
);
1105 const char* colon
= strrchr (sc
, ':');
1108 while (*colon
== ':' && colon
> sc
)
1110 vStringNCopy (scopedName
, scope
, colon
+ 1 - sc
);
1113 if (vStringLength (scopedName
) > 0)
1115 addContextSeparator (scopedName
);
1116 vStringCatS (scopedName
, e
->name
);
1117 e
->name
= vStringValue (scopedName
);
1120 vStringDelete (scopedName
);
1124 static void makeTag (const tokenInfo
*const token
,
1125 const statementInfo
*const st
,
1126 boolean isFileScope
, const tagType type
)
1128 /* Nothing is really of file scope when it appears in a header file.
1130 isFileScope
= (boolean
) (isFileScope
&& ! isHeaderFile ());
1132 if (isType (token
, TOKEN_NAME
) && vStringLength (token
->name
) > 0 &&
1133 includeTag (type
, isFileScope
))
1135 vString
*scope
= vStringNew ();
1136 /* Use "typeRef" to store the typename from addOtherFields() until
1137 * it's used in makeTagEntry().
1139 vString
*typeRef
= vStringNew ();
1142 initTagEntry (&e
, vStringValue (token
->name
));
1144 e
.lineNumber
= token
->lineNumber
;
1145 e
.filePosition
= token
->filePosition
;
1146 e
.isFileScope
= isFileScope
;
1147 e
.kindName
= tagName (type
);
1148 e
.kind
= tagLetter (type
);
1150 findScopeHierarchy (scope
, st
);
1151 addOtherFields (&e
, type
, st
, scope
, typeRef
);
1154 makeExtraTagEntry (type
, &e
, scope
);
1155 vStringDelete (scope
);
1156 vStringDelete (typeRef
);
1160 static boolean
isValidTypeSpecifier (const declType declaration
)
1163 switch (declaration
)
1181 static void qualifyEnumeratorTag (const statementInfo
*const st
,
1182 const tokenInfo
*const nameToken
)
1184 if (isType (nameToken
, TOKEN_NAME
))
1185 makeTag (nameToken
, st
, TRUE
, TAG_ENUMERATOR
);
1188 static void qualifyFunctionTag (const statementInfo
*const st
,
1189 const tokenInfo
*const nameToken
)
1191 if (isType (nameToken
, TOKEN_NAME
))
1194 const boolean isFileScope
=
1195 (boolean
) (st
->member
.access
== ACCESS_PRIVATE
||
1196 (!isMember (st
) && st
->scope
== SCOPE_STATIC
));
1197 if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
))
1199 else if (isLanguage (Lang_vera
) && st
->declaration
== DECL_TASK
)
1202 type
= TAG_FUNCTION
;
1203 makeTag (nameToken
, st
, isFileScope
, type
);
1207 static void qualifyFunctionDeclTag (const statementInfo
*const st
,
1208 const tokenInfo
*const nameToken
)
1210 if (! isType (nameToken
, TOKEN_NAME
))
1212 else if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
))
1213 qualifyFunctionTag (st
, nameToken
);
1214 else if (st
->scope
== SCOPE_TYPEDEF
)
1215 makeTag (nameToken
, st
, TRUE
, TAG_TYPEDEF
);
1216 else if (isValidTypeSpecifier (st
->declaration
) && ! isLanguage (Lang_csharp
))
1217 makeTag (nameToken
, st
, TRUE
, TAG_PROTOTYPE
);
1220 static void qualifyCompoundTag (const statementInfo
*const st
,
1221 const tokenInfo
*const nameToken
)
1223 if (isType (nameToken
, TOKEN_NAME
))
1225 const tagType type
= declToTagType (st
->declaration
);
1226 const boolean fileScoped
= (boolean
)
1227 (!(isLanguage (Lang_java
) ||
1228 isLanguage (Lang_csharp
) ||
1229 isLanguage (Lang_vera
)));
1231 if (type
!= TAG_UNDEFINED
)
1232 makeTag (nameToken
, st
, fileScoped
, type
);
1236 static void qualifyBlockTag (statementInfo
*const st
,
1237 const tokenInfo
*const nameToken
)
1239 switch (st
->declaration
)
1243 case DECL_INTERFACE
:
1244 case DECL_NAMESPACE
:
1248 qualifyCompoundTag (st
, nameToken
);
1254 static void qualifyVariableTag (const statementInfo
*const st
,
1255 const tokenInfo
*const nameToken
)
1257 /* We have to watch that we do not interpret a declaration of the
1258 * form "struct tag;" as a variable definition. In such a case, the
1259 * token preceding the name will be a keyword.
1261 if (! isType (nameToken
, TOKEN_NAME
))
1263 else if (st
->scope
== SCOPE_TYPEDEF
)
1264 makeTag (nameToken
, st
, TRUE
, TAG_TYPEDEF
);
1265 else if (st
->declaration
== DECL_EVENT
)
1266 makeTag (nameToken
, st
, (boolean
) (st
->member
.access
== ACCESS_PRIVATE
),
1268 else if (st
->declaration
== DECL_PACKAGE
)
1269 makeTag (nameToken
, st
, FALSE
, TAG_PACKAGE
);
1270 else if (isValidTypeSpecifier (st
->declaration
))
1272 if (st
->notVariable
)
1274 else if (isMember (st
))
1276 if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
))
1277 makeTag (nameToken
, st
,
1278 (boolean
) (st
->member
.access
== ACCESS_PRIVATE
), TAG_FIELD
);
1279 else if (st
->scope
== SCOPE_GLOBAL
|| st
->scope
== SCOPE_STATIC
)
1280 makeTag (nameToken
, st
, TRUE
, TAG_MEMBER
);
1284 if (st
->scope
== SCOPE_EXTERN
|| ! st
->haveQualifyingName
)
1285 makeTag (nameToken
, st
, FALSE
, TAG_EXTERN_VAR
);
1286 else if (st
->inFunction
)
1287 makeTag (nameToken
, st
, (boolean
) (st
->scope
== SCOPE_STATIC
),
1290 makeTag (nameToken
, st
, (boolean
) (st
->scope
== SCOPE_STATIC
),
1300 static int skipToOneOf (const char *const chars
)
1305 while (c
!= EOF
&& c
!= '\0' && strchr (chars
, c
) == NULL
);
1309 /* Skip to the next non-white character.
1311 static int skipToNonWhite (void)
1313 boolean found
= FALSE
;
1319 while (isspace (c
));
1329 if (CollectingSignature
&& found
)
1330 vStringPut (Signature
, ' ');
1336 /* Skips to the next brace in column 1. This is intended for cases where
1337 * preprocessor constructs result in unbalanced braces.
1339 static void skipToFormattedBraceMatch (void)
1345 while (c
!= EOF
&& (c
!= '\n' || next
!= '}'))
1352 /* Skip to the matching character indicated by the pair string. If skipping
1353 * to a matching brace and any brace is found within a different level of a
1354 * #if conditional statement while brace formatting is in effect, we skip to
1355 * the brace matched by its formatting. It is assumed that we have already
1356 * read the character which starts the group (i.e. the first character of
1359 static void skipToMatch (const char *const pair
)
1361 const boolean braceMatching
= (boolean
) (strcmp ("{}", pair
) == 0);
1362 const boolean braceFormatting
= (boolean
) (isBraceFormat () && braceMatching
);
1363 const unsigned int initialLevel
= getDirectiveNestLevel ();
1364 const int begin
= pair
[0], end
= pair
[1];
1365 const unsigned long inputLineNumber
= getInputLineNumber ();
1369 while (matchLevel
> 0 && (c
= skipToNonWhite ()) != EOF
)
1371 if (CollectingSignature
)
1372 vStringPut (Signature
, c
);
1376 if (braceFormatting
&& getDirectiveNestLevel () != initialLevel
)
1378 skipToFormattedBraceMatch ();
1385 if (braceFormatting
&& getDirectiveNestLevel () != initialLevel
)
1387 skipToFormattedBraceMatch ();
1394 verbose ("%s: failed to find match for '%c' at line %lu\n",
1395 getInputFileName (), begin
, inputLineNumber
);
1397 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
1399 longjmp (Exception
, (int) ExceptionFormattingError
);
1403 static void skipParens (void)
1405 const int c
= skipToNonWhite ();
1413 static void skipBraces (void)
1415 const int c
= skipToNonWhite ();
1423 static keywordId
analyzeKeyword (const char *const name
)
1425 const keywordId id
= (keywordId
) lookupKeyword (name
, getSourceLanguage ());
1429 static void analyzeIdentifier (tokenInfo
*const token
)
1431 char *const name
= vStringValue (token
->name
);
1432 const char *replacement
= NULL
;
1433 boolean parensToo
= FALSE
;
1435 if (isLanguage (Lang_java
) ||
1436 ! isIgnoreToken (name
, &parensToo
, &replacement
))
1438 if (replacement
!= NULL
)
1439 token
->keyword
= analyzeKeyword (replacement
);
1441 token
->keyword
= analyzeKeyword (vStringValue (token
->name
));
1443 if (token
->keyword
== KEYWORD_NONE
)
1444 token
->type
= TOKEN_NAME
;
1446 token
->type
= TOKEN_KEYWORD
;
1453 int c
= skipToNonWhite ();
1461 static void readIdentifier (tokenInfo
*const token
, const int firstChar
)
1463 vString
*const name
= token
->name
;
1465 boolean first
= TRUE
;
1471 vStringPut (name
, c
);
1472 if (CollectingSignature
)
1475 vStringPut (Signature
, c
);
1479 } while (isident (c
) || (isLanguage (Lang_java
) && isHighChar (c
)));
1480 vStringTerminate (name
);
1481 cppUngetc (c
); /* unget non-identifier character */
1483 analyzeIdentifier (token
);
1486 static void readPackageName (tokenInfo
*const token
, const int firstChar
)
1488 vString
*const name
= token
->name
;
1493 while (isident (c
) || c
== '.')
1495 vStringPut (name
, c
);
1498 vStringTerminate (name
);
1499 cppUngetc (c
); /* unget non-package character */
1502 static void readPackage (statementInfo
*const st
)
1504 tokenInfo
*const token
= activeToken (st
);
1505 Assert (isType (token
, TOKEN_KEYWORD
));
1506 readPackageName (token
, skipToNonWhite ());
1507 token
->type
= TOKEN_NAME
;
1508 st
->declaration
= DECL_PACKAGE
;
1510 st
->haveQualifyingName
= TRUE
;
1513 static void processName (statementInfo
*const st
)
1515 Assert (isType (activeToken (st
), TOKEN_NAME
));
1516 if (st
->gotName
&& st
->declaration
== DECL_NONE
)
1517 st
->declaration
= DECL_BASE
;
1519 st
->haveQualifyingName
= TRUE
;
1522 static void readOperator (statementInfo
*const st
)
1524 const char *const acceptable
= "+-*/%^&|~!=<>,[]";
1525 const tokenInfo
* const prev
= prevToken (st
,1);
1526 tokenInfo
*const token
= activeToken (st
);
1527 vString
*const name
= token
->name
;
1528 int c
= skipToNonWhite ();
1530 /* When we arrive here, we have the keyword "operator" in 'name'.
1532 if (isType (prev
, TOKEN_KEYWORD
) && (prev
->keyword
== KEYWORD_ENUM
||
1533 prev
->keyword
== KEYWORD_STRUCT
|| prev
->keyword
== KEYWORD_UNION
))
1534 ; /* ignore "operator" keyword if preceded by these keywords */
1537 /* Verify whether this is a valid function call (i.e. "()") operator.
1539 if (cppGetc () == ')')
1541 vStringPut (name
, ' '); /* always separate operator from keyword */
1542 c
= skipToNonWhite ();
1544 vStringCatS (name
, "()");
1552 else if (isident1 (c
))
1554 /* Handle "new" and "delete" operators, and conversion functions
1555 * (per 13.3.1.1.2 [2] of the C++ spec).
1557 boolean whiteSpace
= TRUE
; /* default causes insertion of space */
1566 vStringPut (name
, ' ');
1569 vStringPut (name
, c
);
1572 } while (! isOneOf (c
, "(;") && c
!= EOF
);
1573 vStringTerminate (name
);
1575 else if (isOneOf (c
, acceptable
))
1577 vStringPut (name
, ' '); /* always separate operator from keyword */
1580 vStringPut (name
, c
);
1582 } while (isOneOf (c
, acceptable
));
1583 vStringTerminate (name
);
1588 token
->type
= TOKEN_NAME
;
1589 token
->keyword
= KEYWORD_NONE
;
1593 static void copyToken (tokenInfo
*const dest
, const tokenInfo
*const src
)
1595 dest
->type
= src
->type
;
1596 dest
->keyword
= src
->keyword
;
1597 dest
->filePosition
= src
->filePosition
;
1598 dest
->lineNumber
= src
->lineNumber
;
1599 vStringCopy (dest
->name
, src
->name
);
1602 static void setAccess (statementInfo
*const st
, const accessType access
)
1606 if (isLanguage (Lang_cpp
))
1608 int c
= skipToNonWhite ();
1611 reinitStatement (st
, FALSE
);
1615 st
->member
.accessDefault
= access
;
1617 st
->member
.access
= access
;
1621 static void discardTypeList (tokenInfo
*const token
)
1623 int c
= skipToNonWhite ();
1624 while (isident1 (c
))
1626 readIdentifier (token
, c
);
1627 c
= skipToNonWhite ();
1628 if (c
== '.' || c
== ',')
1629 c
= skipToNonWhite ();
1634 static void addParentClass (statementInfo
*const st
, tokenInfo
*const token
)
1636 if (vStringLength (token
->name
) > 0 &&
1637 vStringLength (st
->parentClasses
) > 0)
1639 vStringPut (st
->parentClasses
, ',');
1641 vStringCat (st
->parentClasses
, token
->name
);
1644 static void readParents (statementInfo
*const st
, const int qualifier
)
1646 tokenInfo
*const token
= newToken ();
1647 tokenInfo
*const parent
= newToken ();
1652 c
= skipToNonWhite ();
1655 readIdentifier (token
, c
);
1656 if (isType (token
, TOKEN_NAME
))
1657 vStringCat (parent
->name
, token
->name
);
1660 addParentClass (st
, parent
);
1664 else if (c
== qualifier
)
1665 vStringPut (parent
->name
, c
);
1668 else if (isType (token
, TOKEN_NAME
))
1670 addParentClass (st
, parent
);
1673 } while (c
!= '{' && c
!= EOF
);
1675 deleteToken (parent
);
1676 deleteToken (token
);
1679 static void skipStatement (statementInfo
*const st
)
1681 st
->declaration
= DECL_IGNORE
;
1685 static void processToken (tokenInfo
*const token
, statementInfo
*const st
)
1687 switch (token
->keyword
) /* is it a reserved word? */
1691 case KEYWORD_NONE
: processName (st
); break;
1692 case KEYWORD_ABSTRACT
: st
->implementation
= IMP_ABSTRACT
; break;
1693 case KEYWORD_ATTRIBUTE
: skipParens (); initToken (token
); break;
1694 case KEYWORD_BIND
: st
->declaration
= DECL_BASE
; break;
1695 case KEYWORD_BIT
: st
->declaration
= DECL_BASE
; break;
1696 case KEYWORD_CATCH
: skipParens (); skipBraces (); break;
1697 case KEYWORD_CHAR
: st
->declaration
= DECL_BASE
; break;
1698 case KEYWORD_CLASS
: st
->declaration
= DECL_CLASS
; break;
1699 case KEYWORD_CONST
: st
->declaration
= DECL_BASE
; break;
1700 case KEYWORD_DOUBLE
: st
->declaration
= DECL_BASE
; break;
1701 case KEYWORD_ENUM
: st
->declaration
= DECL_ENUM
; break;
1702 case KEYWORD_EXTENDS
: readParents (st
, '.');
1703 setToken (st
, TOKEN_NONE
); break;
1704 case KEYWORD_FLOAT
: st
->declaration
= DECL_BASE
; break;
1705 case KEYWORD_FUNCTION
: st
->declaration
= DECL_BASE
; break;
1706 case KEYWORD_FRIEND
: st
->scope
= SCOPE_FRIEND
; break;
1707 case KEYWORD_GOTO
: skipStatement (st
); break;
1708 case KEYWORD_IMPLEMENTS
:readParents (st
, '.');
1709 setToken (st
, TOKEN_NONE
); break;
1710 case KEYWORD_IMPORT
: skipStatement (st
); break;
1711 case KEYWORD_INT
: st
->declaration
= DECL_BASE
; break;
1712 case KEYWORD_INTEGER
: st
->declaration
= DECL_BASE
; break;
1713 case KEYWORD_INTERFACE
: st
->declaration
= DECL_INTERFACE
; break;
1714 case KEYWORD_LOCAL
: setAccess (st
, ACCESS_LOCAL
); break;
1715 case KEYWORD_LONG
: st
->declaration
= DECL_BASE
; break;
1716 case KEYWORD_NAMESPACE
: st
->declaration
= DECL_NAMESPACE
; break;
1717 case KEYWORD_OPERATOR
: readOperator (st
); break;
1718 case KEYWORD_PACKAGE
: readPackage (st
); break;
1719 case KEYWORD_PRIVATE
: setAccess (st
, ACCESS_PRIVATE
); break;
1720 case KEYWORD_PROGRAM
: st
->declaration
= DECL_PROGRAM
; break;
1721 case KEYWORD_PROTECTED
: setAccess (st
, ACCESS_PROTECTED
); break;
1722 case KEYWORD_PUBLIC
: setAccess (st
, ACCESS_PUBLIC
); break;
1723 case KEYWORD_RETURN
: skipStatement (st
); break;
1724 case KEYWORD_SHORT
: st
->declaration
= DECL_BASE
; break;
1725 case KEYWORD_SIGNED
: st
->declaration
= DECL_BASE
; break;
1726 case KEYWORD_STRING
: st
->declaration
= DECL_BASE
; break;
1727 case KEYWORD_STRUCT
: st
->declaration
= DECL_STRUCT
; break;
1728 case KEYWORD_TASK
: st
->declaration
= DECL_TASK
; break;
1729 case KEYWORD_THROWS
: discardTypeList (token
); break;
1730 case KEYWORD_UNION
: st
->declaration
= DECL_UNION
; break;
1731 case KEYWORD_UNSIGNED
: st
->declaration
= DECL_BASE
; break;
1732 case KEYWORD_USING
: skipStatement (st
); break;
1733 case KEYWORD_VOID
: st
->declaration
= DECL_BASE
; break;
1734 case KEYWORD_VOLATILE
: st
->declaration
= DECL_BASE
; break;
1735 case KEYWORD_VIRTUAL
: st
->implementation
= IMP_VIRTUAL
; break;
1738 if (isLanguage (Lang_csharp
))
1739 st
->declaration
= DECL_EVENT
;
1742 case KEYWORD_TYPEDEF
:
1743 reinitStatement (st
, FALSE
);
1744 st
->scope
= SCOPE_TYPEDEF
;
1747 case KEYWORD_EXTERN
:
1748 if (! isLanguage (Lang_csharp
) || !st
->gotName
)
1750 reinitStatement (st
, FALSE
);
1751 st
->scope
= SCOPE_EXTERN
;
1752 st
->declaration
= DECL_BASE
;
1756 case KEYWORD_STATIC
:
1757 if (! (isLanguage (Lang_java
) || isLanguage (Lang_csharp
)))
1759 reinitStatement (st
, FALSE
);
1760 st
->scope
= SCOPE_STATIC
;
1761 st
->declaration
= DECL_BASE
;
1767 case KEYWORD_SWITCH
:
1770 int c
= skipToNonWhite ();
1779 * Parenthesis handling functions
1782 static void restartStatement (statementInfo
*const st
)
1784 tokenInfo
*const save
= newToken ();
1785 tokenInfo
*token
= activeToken (st
);
1787 copyToken (save
, token
);
1788 DebugStatement ( if (debug (DEBUG_PARSE
)) printf ("<ES>");)
1789 reinitStatement (st
, FALSE
);
1790 token
= activeToken (st
);
1791 copyToken (token
, save
);
1793 processToken (token
, st
);
1796 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
1798 * mem-initializer-list:
1799 * mem-initializer, mem-initializer-list
1802 * [::] [nested-name-spec] class-name (...)
1805 static void skipMemIntializerList (tokenInfo
*const token
)
1811 c
= skipToNonWhite ();
1812 while (isident1 (c
) || c
== ':')
1815 readIdentifier (token
, c
);
1816 c
= skipToNonWhite ();
1821 c
= skipToNonWhite ();
1826 c
= skipToNonWhite ();
1832 static void skipMacro (statementInfo
*const st
)
1834 tokenInfo
*const prev2
= prevToken (st
, 2);
1836 if (isType (prev2
, TOKEN_NAME
))
1841 /* Skips over characters following the parameter list. This will be either
1842 * non-ANSI style function declarations or C++ stuff. Our choices:
1846 * int func (one, two) int one; float two; {...}
1848 * int func (int one, float two);
1849 * int func (int one, float two) {...}
1851 * int foo (...) [const|volatile] [throw (...)];
1852 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
1853 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
1856 static boolean
skipPostArgumentStuff (
1857 statementInfo
*const st
, parenInfo
*const info
)
1859 tokenInfo
*const token
= activeToken (st
);
1860 unsigned int parameters
= info
->parameterCount
;
1861 unsigned int elementCount
= 0;
1862 boolean restart
= FALSE
;
1863 boolean end
= FALSE
;
1864 int c
= skipToNonWhite ();
1871 case ':': skipMemIntializerList (token
);break; /* ctor-initializer */
1872 case '[': skipToMatch ("[]"); break;
1873 case '=': cppUngetc (c
); end
= TRUE
; break;
1874 case '{': cppUngetc (c
); end
= TRUE
; break;
1875 case '}': cppUngetc (c
); end
= TRUE
; break;
1878 if (elementCount
> 0)
1884 if (parameters
== 0 || elementCount
< 2)
1889 else if (--parameters
== 0)
1896 readIdentifier (token
, c
);
1897 switch (token
->keyword
)
1899 case KEYWORD_ATTRIBUTE
: skipParens (); break;
1900 case KEYWORD_THROW
: skipParens (); break;
1901 case KEYWORD_TRY
: break;
1904 case KEYWORD_VOLATILE
:
1905 if (vStringLength (Signature
) > 0)
1907 vStringPut (Signature
, ' ');
1908 vStringCat (Signature
, token
->name
);
1914 case KEYWORD_EXPLICIT
:
1915 case KEYWORD_EXTERN
:
1916 case KEYWORD_FRIEND
:
1917 case KEYWORD_INLINE
:
1918 case KEYWORD_MUTABLE
:
1919 case KEYWORD_NAMESPACE
:
1921 case KEYWORD_NEWCOV
:
1922 case KEYWORD_OPERATOR
:
1923 case KEYWORD_OVERLOAD
:
1924 case KEYWORD_PRIVATE
:
1925 case KEYWORD_PROTECTED
:
1926 case KEYWORD_PUBLIC
:
1927 case KEYWORD_STATIC
:
1928 case KEYWORD_TEMPLATE
:
1929 case KEYWORD_TYPEDEF
:
1930 case KEYWORD_TYPENAME
:
1932 case KEYWORD_VIRTUAL
:
1933 /* Never allowed within parameter declarations. */
1939 if (isType (token
, TOKEN_NONE
))
1941 else if (info
->isKnrParamList
&& info
->parameterCount
> 0)
1945 /* If we encounter any other identifier immediately
1946 * following an empty parameter list, this is almost
1947 * certainly one of those Microsoft macro "thingies"
1948 * that the automatic source code generation sticks
1949 * in. Terminate the current statement.
1960 c
= skipToNonWhite ();
1967 restartStatement (st
);
1969 setToken (st
, TOKEN_NONE
);
1971 return (boolean
) (c
!= EOF
);
1974 static void skipJavaThrows (statementInfo
*const st
)
1976 tokenInfo
*const token
= activeToken (st
);
1977 int c
= skipToNonWhite ();
1981 readIdentifier (token
, c
);
1982 if (token
->keyword
== KEYWORD_THROWS
)
1986 c
= skipToNonWhite ();
1989 readIdentifier (token
, c
);
1990 c
= skipToNonWhite ();
1992 } while (c
== '.' || c
== ',');
1996 setToken (st
, TOKEN_NONE
);
1999 static void analyzePostParens (statementInfo
*const st
, parenInfo
*const info
)
2001 const unsigned long inputLineNumber
= getInputLineNumber ();
2002 int c
= skipToNonWhite ();
2005 if (isOneOf (c
, "{;,="))
2007 else if (isLanguage (Lang_java
))
2008 skipJavaThrows (st
);
2011 if (! skipPostArgumentStuff (st
, info
))
2014 "%s: confusing argument declarations beginning at line %lu\n",
2015 getInputFileName (), inputLineNumber
);
2016 longjmp (Exception
, (int) ExceptionFormattingError
);
2021 static int parseParens (statementInfo
*const st
, parenInfo
*const info
)
2023 tokenInfo
*const token
= activeToken (st
);
2024 unsigned int identifierCount
= 0;
2025 unsigned int depth
= 1;
2026 boolean firstChar
= TRUE
;
2027 int nextChar
= '\0';
2029 CollectingSignature
= TRUE
;
2030 vStringClear (Signature
);
2031 vStringPut (Signature
, '(');
2032 info
->parameterCount
= 1;
2035 int c
= skipToNonWhite ();
2036 vStringPut (Signature
, c
);
2042 info
->isPointer
= TRUE
;
2043 info
->isKnrParamList
= FALSE
;
2044 if (identifierCount
== 0)
2045 info
->isParamList
= FALSE
;
2050 info
->isKnrParamList
= FALSE
;
2054 info
->isNameCandidate
= FALSE
;
2059 info
->isKnrParamList
= FALSE
;
2067 info
->isKnrParamList
= FALSE
;
2070 vStringCatS (Signature
, "..."); /* variable arg list */
2075 info
->isNameCandidate
= FALSE
;
2076 if (info
->isKnrParamList
)
2078 ++info
->parameterCount
;
2079 identifierCount
= 0;
2084 info
->isKnrParamList
= FALSE
;
2085 info
->isNameCandidate
= FALSE
;
2088 info
->isParamList
= FALSE
;
2095 info
->isKnrParamList
= FALSE
;
2100 info
->isKnrParamList
= FALSE
;
2106 info
->parameterCount
= 0;
2111 info
->isKnrParamList
= FALSE
;
2114 info
->isNameCandidate
= FALSE
;
2116 vStringClear (Signature
);
2119 vStringChop (Signature
);
2121 else if (isType (token
, TOKEN_PAREN_NAME
))
2123 c
= skipToNonWhite ();
2124 if (c
== '*') /* check for function pointer */
2127 c
= skipToNonWhite ();
2137 info
->nestedArgs
= TRUE
;
2147 if (++identifierCount
> 1)
2148 info
->isKnrParamList
= FALSE
;
2149 readIdentifier (token
, c
);
2150 if (isType (token
, TOKEN_NAME
) && info
->isNameCandidate
)
2151 token
->type
= TOKEN_PAREN_NAME
;
2152 else if (isType (token
, TOKEN_KEYWORD
))
2154 if (token
->keyword
!= KEYWORD_CONST
&&
2155 token
->keyword
!= KEYWORD_VOLATILE
)
2157 info
->isKnrParamList
= FALSE
;
2158 info
->isNameCandidate
= FALSE
;
2164 info
->isParamList
= FALSE
;
2165 info
->isKnrParamList
= FALSE
;
2166 info
->isNameCandidate
= FALSE
;
2167 info
->invalidContents
= TRUE
;
2172 } while (! info
->nestedArgs
&& depth
> 0 &&
2173 (info
->isKnrParamList
|| info
->isNameCandidate
));
2175 if (! info
->nestedArgs
) while (depth
> 0)
2181 if (! info
->isNameCandidate
)
2184 vStringTerminate (Signature
);
2185 if (info
->isKnrParamList
)
2186 vStringClear (Signature
);
2187 CollectingSignature
= FALSE
;
2191 static void initParenInfo (parenInfo
*const info
)
2193 info
->isPointer
= FALSE
;
2194 info
->isParamList
= TRUE
;
2195 info
->isKnrParamList
= isLanguage (Lang_c
);
2196 info
->isNameCandidate
= TRUE
;
2197 info
->invalidContents
= FALSE
;
2198 info
->nestedArgs
= FALSE
;
2199 info
->parameterCount
= 0;
2202 static void analyzeParens (statementInfo
*const st
)
2204 tokenInfo
*const prev
= prevToken (st
, 1);
2206 if (st
->inFunction
&& ! st
->assignment
)
2207 st
->notVariable
= TRUE
;
2208 if (! isType (prev
, TOKEN_NONE
)) /* in case of ignored enclosing macros */
2210 tokenInfo
*const token
= activeToken (st
);
2214 initParenInfo (&info
);
2215 parseParens (st
, &info
);
2216 c
= skipToNonWhite ();
2218 if (info
.invalidContents
)
2219 reinitStatement (st
, FALSE
);
2220 else if (info
.isNameCandidate
&& isType (token
, TOKEN_PAREN_NAME
) &&
2221 ! st
->gotParenName
&&
2222 (! info
.isParamList
|| ! st
->haveQualifyingName
||
2224 (c
== '=' && st
->implementation
!= IMP_VIRTUAL
) ||
2225 (st
->declaration
== DECL_NONE
&& isOneOf (c
, ",;"))))
2227 token
->type
= TOKEN_NAME
;
2229 st
->gotParenName
= TRUE
;
2230 if (! (c
== '(' && info
.nestedArgs
))
2231 st
->isPointer
= info
.isPointer
;
2233 else if (! st
->gotArgs
&& info
.isParamList
)
2236 setToken (st
, TOKEN_ARGS
);
2238 if (st
->scope
!= SCOPE_TYPEDEF
)
2239 analyzePostParens (st
, &info
);
2242 setToken (st
, TOKEN_NONE
);
2247 * Token parsing functions
2250 static void addContext (statementInfo
*const st
, const tokenInfo
* const token
)
2252 if (isType (token
, TOKEN_NAME
))
2254 if (vStringLength (st
->context
->name
) > 0)
2256 if (isLanguage (Lang_c
) || isLanguage (Lang_cpp
))
2257 vStringCatS (st
->context
->name
, "::");
2258 else if (isLanguage (Lang_java
) || isLanguage (Lang_csharp
))
2259 vStringCatS (st
->context
->name
, ".");
2261 vStringCat (st
->context
->name
, token
->name
);
2262 st
->context
->type
= TOKEN_NAME
;
2266 static boolean
inheritingDeclaration (declType decl
)
2269 decl
== DECL_CLASS
||
2270 decl
== DECL_STRUCT
||
2271 decl
== DECL_INTERFACE
);
2274 static void processColon (statementInfo
*const st
)
2276 int c
= skipToNonWhite ();
2277 const boolean doubleColon
= (boolean
) (c
== ':');
2281 setToken (st
, TOKEN_DOUBLE_COLON
);
2282 st
->haveQualifyingName
= FALSE
;
2287 if ((isLanguage (Lang_cpp
) || isLanguage (Lang_csharp
)) &&
2288 inheritingDeclaration (st
->declaration
))
2290 readParents (st
, ':');
2292 else if (parentDecl (st
) == DECL_STRUCT
)
2294 c
= skipToOneOf (",;");
2296 setToken (st
, TOKEN_COMMA
);
2298 setToken (st
, TOKEN_SEMICOLON
);
2302 const tokenInfo
*const prev
= prevToken (st
, 1);
2303 const tokenInfo
*const prev2
= prevToken (st
, 2);
2304 if (prev
->keyword
== KEYWORD_DEFAULT
||
2305 prev2
->keyword
== KEYWORD_CASE
||
2308 reinitStatement (st
, FALSE
);
2314 static void processAngleBracket (void)
2318 ; /* already found match for template */
2319 else if ((isLanguage (Lang_cpp
) || isLanguage (Lang_java
)) &&
2320 c
!= '<' && c
!= '=')
2322 skipToMatch ("<>"); /* this is a template */
2328 /* Skips over any initializing value which may follow an '=' character in a
2329 * variable definition.
2331 static int skipInitializer (statementInfo
*const st
)
2333 boolean done
= FALSE
;
2338 c
= skipToNonWhite ();
2341 longjmp (Exception
, (int) ExceptionFormattingError
);
2345 case ';': done
= TRUE
; break;
2348 if (st
->implementation
== IMP_VIRTUAL
)
2349 st
->implementation
= IMP_PURE_VIRTUAL
;
2352 case '[': skipToMatch ("[]"); break;
2353 case '(': skipToMatch ("()"); break;
2354 case '{': skipToMatch ("{}"); break;
2357 if (insideEnumBody (st
))
2359 else if (! isBraceFormat ())
2361 verbose ("%s: unexpected closing brace at line %lu\n",
2362 getInputFileName (), getInputLineNumber ());
2363 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
2373 static void processInitializer (statementInfo
*const st
)
2375 const boolean inEnumBody
= insideEnumBody (st
);
2381 c
= skipInitializer (st
);
2382 st
->assignment
= TRUE
;
2384 setToken (st
, TOKEN_SEMICOLON
);
2386 setToken (st
, TOKEN_COMMA
);
2387 else if ('}' && inEnumBody
)
2390 setToken (st
, TOKEN_COMMA
);
2392 if (st
->scope
== SCOPE_EXTERN
)
2393 st
->scope
= SCOPE_GLOBAL
;
2397 static void parseIdentifier (statementInfo
*const st
, const int c
)
2399 tokenInfo
*const token
= activeToken (st
);
2401 readIdentifier (token
, c
);
2402 if (! isType (token
, TOKEN_NONE
))
2403 processToken (token
, st
);
2406 static void parseGeneralToken (statementInfo
*const st
, const int c
)
2408 const tokenInfo
*const prev
= prevToken (st
, 1);
2410 if (isident1 (c
) || (isLanguage (Lang_java
) && isHighChar (c
)))
2412 parseIdentifier (st
, c
);
2413 if (isType (st
->context
, TOKEN_NAME
) &&
2414 isType (activeToken (st
), TOKEN_NAME
) && isType (prev
, TOKEN_NAME
))
2416 initToken (st
->context
);
2419 else if (c
== '.' || c
== '-')
2421 if (! st
->assignment
)
2422 st
->notVariable
= TRUE
;
2425 int c2
= cppGetc ();
2430 else if (c
== '!' || c
== '>')
2432 int c2
= cppGetc ();
2436 else if (isExternCDecl (st
, c
))
2438 st
->declaration
= DECL_NOMANGLE
;
2439 st
->scope
= SCOPE_GLOBAL
;
2443 /* Reads characters from the pre-processor and assembles tokens, setting
2444 * the current statement state.
2446 static void nextToken (statementInfo
*const st
)
2451 int c
= skipToNonWhite ();
2454 case EOF
: longjmp (Exception
, (int) ExceptionEOF
); break;
2455 case '(': analyzeParens (st
); break;
2456 case '<': processAngleBracket (); break;
2457 case '*': st
->haveQualifyingName
= FALSE
; break;
2458 case ',': setToken (st
, TOKEN_COMMA
); break;
2459 case ':': processColon (st
); break;
2460 case ';': setToken (st
, TOKEN_SEMICOLON
); break;
2461 case '=': processInitializer (st
); break;
2462 case '[': skipToMatch ("[]"); break;
2463 case '{': setToken (st
, TOKEN_BRACE_OPEN
); break;
2464 case '}': setToken (st
, TOKEN_BRACE_CLOSE
); break;
2465 default: parseGeneralToken (st
, c
); break;
2467 token
= activeToken (st
);
2468 } while (isType (token
, TOKEN_NONE
));
2472 * Scanning support functions
2475 static statementInfo
*CurrentStatement
= NULL
;
2477 static statementInfo
*newStatement (statementInfo
*const parent
)
2479 statementInfo
*const st
= xMalloc (1, statementInfo
);
2482 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
2483 st
->token
[i
] = newToken ();
2485 st
->context
= newToken ();
2486 st
->blockName
= newToken ();
2487 st
->parentClasses
= vStringNew ();
2489 initStatement (st
, parent
);
2490 CurrentStatement
= st
;
2495 static void deleteStatement (void)
2497 statementInfo
*const st
= CurrentStatement
;
2498 statementInfo
*const parent
= st
->parent
;
2501 for (i
= 0 ; i
< (unsigned int) NumTokens
; ++i
)
2503 deleteToken (st
->token
[i
]); st
->token
[i
] = NULL
;
2505 deleteToken (st
->blockName
); st
->blockName
= NULL
;
2506 deleteToken (st
->context
); st
->context
= NULL
;
2507 vStringDelete (st
->parentClasses
); st
->parentClasses
= NULL
;
2509 CurrentStatement
= parent
;
2512 static void deleteAllStatements (void)
2514 while (CurrentStatement
!= NULL
)
2518 static boolean
isStatementEnd (const statementInfo
*const st
)
2520 const tokenInfo
*const token
= activeToken (st
);
2523 if (isType (token
, TOKEN_SEMICOLON
))
2525 else if (isType (token
, TOKEN_BRACE_CLOSE
))
2526 /* Java and C# do not require semicolons to end a block. Neither do C++
2527 * namespaces. All other blocks require a semicolon to terminate them.
2529 isEnd
= (boolean
) (isLanguage (Lang_java
) || isLanguage (Lang_csharp
) ||
2530 ! isContextualStatement (st
));
2537 static void checkStatementEnd (statementInfo
*const st
)
2539 const tokenInfo
*const token
= activeToken (st
);
2541 if (isType (token
, TOKEN_COMMA
))
2542 reinitStatement (st
, TRUE
);
2543 else if (isStatementEnd (st
))
2545 DebugStatement ( if (debug (DEBUG_PARSE
)) printf ("<ES>"); )
2546 reinitStatement (st
, FALSE
);
2551 cppBeginStatement ();
2556 static void nest (statementInfo
*const st
, const unsigned int nestLevel
)
2558 switch (st
->declaration
)
2562 case DECL_INTERFACE
:
2563 case DECL_NAMESPACE
:
2567 createTags (nestLevel
, st
);
2572 st
->inFunction
= TRUE
;
2575 if (includeTag (TAG_LOCAL
, FALSE
))
2576 createTags (nestLevel
, st
);
2582 setToken (st
, TOKEN_BRACE_CLOSE
);
2585 static void tagCheck (statementInfo
*const st
)
2587 const tokenInfo
*const token
= activeToken (st
);
2588 const tokenInfo
*const prev
= prevToken (st
, 1);
2589 const tokenInfo
*const prev2
= prevToken (st
, 2);
2591 switch (token
->type
)
2594 if (insideEnumBody (st
))
2595 qualifyEnumeratorTag (st
, token
);
2599 if (st
->haveQualifyingName
)
2600 makeTag (token
, st
, FALSE
, TAG_PACKAGE
);
2603 case TOKEN_BRACE_OPEN
:
2604 if (isType (prev
, TOKEN_ARGS
))
2606 if (st
->haveQualifyingName
)
2608 if (! isLanguage (Lang_vera
))
2609 st
->declaration
= DECL_FUNCTION
;
2610 if (isType (prev2
, TOKEN_NAME
))
2611 copyToken (st
->blockName
, prev2
);
2612 qualifyFunctionTag (st
, prev2
);
2615 else if (isContextualStatement (st
) ||
2616 st
->declaration
== DECL_NAMESPACE
||
2617 st
->declaration
== DECL_PROGRAM
)
2619 if (isType (prev
, TOKEN_NAME
))
2620 copyToken (st
->blockName
, prev
);
2623 /* For an anonymous struct or union we use a unique ID
2624 * a number, so that the members can be found.
2626 char buf
[20]; /* length of "_anon" + digits + null */
2627 sprintf (buf
, "__anon%d", ++AnonymousID
);
2628 vStringCopyS (st
->blockName
->name
, buf
);
2629 st
->blockName
->type
= TOKEN_NAME
;
2630 st
->blockName
->keyword
= KEYWORD_NONE
;
2632 qualifyBlockTag (st
, prev
);
2634 else if (isLanguage (Lang_csharp
))
2635 makeTag (prev
, st
, FALSE
, TAG_PROPERTY
);
2638 case TOKEN_SEMICOLON
:
2640 if (insideEnumBody (st
))
2642 else if (isType (prev
, TOKEN_NAME
))
2644 if (isContextualKeyword (prev2
))
2645 st
->scope
= SCOPE_EXTERN
;
2647 qualifyVariableTag (st
, prev
);
2649 else if (isType (prev
, TOKEN_ARGS
) && isType (prev2
, TOKEN_NAME
))
2652 qualifyVariableTag (st
, prev2
);
2654 qualifyFunctionDeclTag (st
, prev2
);
2662 /* Parses the current file and decides whether to write out and tags that
2665 static void createTags (const unsigned int nestLevel
,
2666 statementInfo
*const parent
)
2668 statementInfo
*const st
= newStatement (parent
);
2670 DebugStatement ( if (nestLevel
> 0) debugParseNest (TRUE
, nestLevel
); )
2676 token
= activeToken (st
);
2677 if (isType (token
, TOKEN_BRACE_CLOSE
))
2683 verbose ("%s: unexpected closing brace at line %lu\n",
2684 getInputFileName (), getInputLineNumber ());
2685 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
2688 else if (isType (token
, TOKEN_DOUBLE_COLON
))
2690 addContext (st
, prevToken (st
, 1));
2696 if (isType (token
, TOKEN_BRACE_OPEN
))
2697 nest (st
, nestLevel
+ 1);
2698 checkStatementEnd (st
);
2702 DebugStatement ( if (nestLevel
> 0) debugParseNest (FALSE
, nestLevel
- 1); )
2705 static boolean
findCTags (const unsigned int passCount
)
2707 exception_t exception
;
2710 Assert (passCount
< 3);
2711 cppInit ((boolean
) (passCount
> 1));
2712 Signature
= vStringNew ();
2714 exception
= (exception_t
) setjmp (Exception
);
2716 if (exception
== ExceptionNone
)
2717 createTags (0, NULL
);
2720 deleteAllStatements ();
2721 if (exception
== ExceptionBraceFormattingError
&& passCount
== 1)
2724 verbose ("%s: retrying file with fallback brace matching algorithm\n",
2725 getInputFileName ());
2728 vStringDelete (Signature
);
2733 static void buildKeywordHash (const langType language
, unsigned int idx
)
2735 const size_t count
= sizeof (KeywordTable
) / sizeof (KeywordTable
[0]);
2737 for (i
= 0 ; i
< count
; ++i
)
2739 const keywordDesc
* const p
= &KeywordTable
[i
];
2740 if (p
->isValid
[idx
])
2741 addKeyword (p
->name
, language
, (int) p
->id
);
2745 static void initializeCParser (const langType language
)
2748 buildKeywordHash (language
, 0);
2751 static void initializeCppParser (const langType language
)
2753 Lang_cpp
= language
;
2754 buildKeywordHash (language
, 1);
2757 static void initializeCsharpParser (const langType language
)
2759 Lang_csharp
= language
;
2760 buildKeywordHash (language
, 2);
2763 static void initializeJavaParser (const langType language
)
2765 Lang_java
= language
;
2766 buildKeywordHash (language
, 3);
2769 static void initializeVeraParser (const langType language
)
2771 Lang_vera
= language
;
2772 buildKeywordHash (language
, 4);
2775 extern parserDefinition
* CParser (void)
2777 static const char *const extensions
[] = { "c", NULL
};
2778 parserDefinition
* def
= parserNew ("C");
2779 def
->kinds
= CKinds
;
2780 def
->kindCount
= KIND_COUNT (CKinds
);
2781 def
->extensions
= extensions
;
2782 def
->parser2
= findCTags
;
2783 def
->initialize
= initializeCParser
;
2787 extern parserDefinition
* CppParser (void)
2789 static const char *const extensions
[] = {
2790 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
2791 #ifndef CASE_INSENSITIVE_FILENAMES
2796 parserDefinition
* def
= parserNew ("C++");
2797 def
->kinds
= CKinds
;
2798 def
->kindCount
= KIND_COUNT (CKinds
);
2799 def
->extensions
= extensions
;
2800 def
->parser2
= findCTags
;
2801 def
->initialize
= initializeCppParser
;
2805 extern parserDefinition
* CsharpParser (void)
2807 static const char *const extensions
[] = { "cs", NULL
};
2808 parserDefinition
* def
= parserNew ("C#");
2809 def
->kinds
= CsharpKinds
;
2810 def
->kindCount
= KIND_COUNT (CsharpKinds
);
2811 def
->extensions
= extensions
;
2812 def
->parser2
= findCTags
;
2813 def
->initialize
= initializeCsharpParser
;
2817 extern parserDefinition
* JavaParser (void)
2819 static const char *const extensions
[] = { "java", NULL
};
2820 parserDefinition
* def
= parserNew ("Java");
2821 def
->kinds
= JavaKinds
;
2822 def
->kindCount
= KIND_COUNT (JavaKinds
);
2823 def
->extensions
= extensions
;
2824 def
->parser2
= findCTags
;
2825 def
->initialize
= initializeJavaParser
;
2829 extern parserDefinition
* VeraParser (void)
2831 static const char *const extensions
[] = { "vr", "vri", "vrh", NULL
};
2832 parserDefinition
* def
= parserNew ("Vera");
2833 def
->kinds
= VeraKinds
;
2834 def
->kindCount
= KIND_COUNT (VeraKinds
);
2835 def
->extensions
= extensions
;
2836 def
->parser2
= findCTags
;
2837 def
->initialize
= initializeVeraParser
;
2841 /* vi:set tabstop=4 shiftwidth=4 noexpandtab: */