Implement status support
[anjuta-git-plugin.git] / tagmanager / c.c
bloba3a9cc5b33e05428683595251c2243db34092e91
1 /*
2 * $Id$
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
10 * source files.
14 * INCLUDE FILES
16 #include "general.h" /* must always come first */
18 #include <string.h>
19 #include <setjmp.h>
21 #include "debug.h"
22 #include "entry.h"
23 #include "get.h"
24 #include "keyword.h"
25 #include "options.h"
26 #include "parse.h"
27 #include "read.h"
28 #include "routines.h"
31 * MACROS
33 #define MaxFields 6
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)
50 * DATA DECLARATIONS
53 enum { NumTokens = 3 };
55 typedef enum eException {
56 ExceptionNone, ExceptionEOF, ExceptionFormattingError,
57 ExceptionBraceFormattingError
58 } exception_t;
60 /* Used to specify type of keyword.
62 typedef enum eKeywordId {
63 KEYWORD_NONE = -1,
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,
70 KEYWORD_DOUBLE,
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,
74 KEYWORD_GOTO,
75 KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_INLINE, KEYWORD_INT,
76 KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
77 KEYWORD_INTERNAL,
78 KEYWORD_LOCAL, KEYWORD_LONG,
79 KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
80 KEYWORD_MUTABLE,
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,
93 KEYWORD_USING,
94 KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
95 KEYWORD_WCHAR_T, KEYWORD_WHILE
96 } keywordId;
98 /* Used to determine whether keyword is valid for the current language and
99 * what its ID is.
101 typedef struct sKeywordDesc {
102 const char *name;
103 keywordId id;
104 short isValid [5]; /* indicates languages for which kw is valid */
105 } keywordDesc;
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 */
112 TOKEN_BRACE_CLOSE,
113 TOKEN_BRACE_OPEN,
114 TOKEN_COLON, /* the colon character */
115 TOKEN_COMMA, /* the comma character */
116 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
117 TOKEN_KEYWORD,
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. */
123 TOKEN_COUNT
124 } tokenType;
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 */
134 SCOPE_COUNT
135 } tagScope;
137 typedef enum eDeclaration {
138 DECL_NONE,
139 DECL_BASE, /* base type (default) */
140 DECL_CLASS,
141 DECL_ENUM,
142 DECL_EVENT,
143 DECL_FUNCTION,
144 DECL_IGNORE, /* non-taggable "declaration" */
145 DECL_INTERFACE,
146 DECL_NAMESPACE,
147 DECL_NOMANGLE, /* C++ name demangling block */
148 DECL_PACKAGE,
149 DECL_PROGRAM, /* Vera program */
150 DECL_STRUCT,
151 DECL_TASK, /* Vera task */
152 DECL_UNION,
153 DECL_COUNT
154 } declType;
156 typedef enum eVisibilityType {
157 ACCESS_UNDEFINED,
158 ACCESS_LOCAL,
159 ACCESS_PRIVATE,
160 ACCESS_PROTECTED,
161 ACCESS_PUBLIC,
162 ACCESS_DEFAULT, /* Java-specific */
163 ACCESS_COUNT
164 } accessType;
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 */
171 } memberInfo;
173 typedef struct sTokenInfo {
174 tokenType type;
175 keywordId keyword;
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 */
179 } tokenInfo;
181 typedef enum eImplementation {
182 IMP_DEFAULT,
183 IMP_ABSTRACT,
184 IMP_VIRTUAL,
185 IMP_PURE_VIRTUAL,
186 IMP_COUNT
187 } impType;
189 /* Describes the statement currently undergoing analysis.
191 typedef struct sStatementInfo {
192 tagScope scope;
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 */
210 } statementInfo;
212 /* Describes the type of tag being generated.
214 typedef enum eTagType {
215 TAG_UNDEFINED,
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 */
238 } tagType;
240 typedef struct sParenInfo {
241 boolean isPointer;
242 boolean isParamList;
243 boolean isKnrParamList;
244 boolean isNameCandidate;
245 boolean invalidContents;
246 boolean nestedArgs;
247 unsigned int parameterCount;
248 } parenInfo;
251 * DATA DEFINITIONS
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. */
268 typedef enum {
269 CK_UNDEFINED = -1,
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,
273 CK_EXTERN_VARIABLE
274 } cKind;
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"},
293 typedef enum {
294 CSK_UNDEFINED = -1,
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
298 } csharpKind;
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. */
317 typedef enum {
318 JK_UNDEFINED = -1,
319 JK_CLASS, JK_FIELD, JK_INTERFACE, JK_LOCAL, JK_METHOD,
320 JK_PACKAGE, JK_ACCESS, JK_CLASS_PREFIX
321 } javaKind;
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. */
333 typedef enum {
334 VK_UNDEFINED = -1,
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,
338 VK_EXTERN_VARIABLE
339 } veraKind;
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 [] = {
358 /* C++ */
359 /* ANSI C | C# Java */
360 /* | | | | Vera */
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;
478 * Token management
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)
493 st->tokenIndex = 0;
494 else
495 ++st->tokenIndex;
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;
503 Assert (n < num);
504 tokenIndex = (st->tokenIndex + num - n) % num;
505 return st->token [tokenIndex];
508 static void setToken (statementInfo *const st, const tokenType type)
510 tokenInfo *token;
511 token = activeToken (st);
512 initToken (token);
513 token->type = type;
516 static void retardToken (statementInfo *const st)
518 if (st->tokenIndex == 0)
519 st->tokenIndex = (unsigned int) NumTokens - 1;
520 else
521 --st->tokenIndex;
522 setToken (st, TOKEN_NONE);
525 static tokenInfo *newToken (void)
527 tokenInfo *const token = xMalloc (1, tokenInfo);
528 token->name = vStringNew ();
529 initToken (token);
530 return token;
533 static void deleteToken (tokenInfo *const token)
535 if (token != NULL)
537 vStringDelete (token->name);
538 eFree (token);
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
566 #ifdef DEBUG
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";
607 size_t i;
608 for (i = 0 ; i < count ; ++i)
610 const keywordDesc *p = &KeywordTable [i];
611 if (p->id == keyword)
613 name = p->name;
614 break;
617 return name;
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),
625 token->lineNumber);
626 else if (isType (token, TOKEN_KEYWORD))
627 printf ("type: %-12s: %-13s line: %lu\n",
628 tokenString (token->type), keywordString (token->keyword),
629 token->lineNumber);
630 else
631 printf ("type: %-12s line: %lu\n",
632 tokenString (token->type), token->lineNumber);
635 static void __unused__ ps (statementInfo *const st)
637 unsigned int i;
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));
644 printf ("token : ");
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: ");
652 pt (st->context);
655 #endif
658 * Statement management
661 static boolean isContextualKeyword (const tokenInfo *const token)
663 boolean result;
664 switch (token->keyword)
666 case KEYWORD_CLASS:
667 case KEYWORD_ENUM:
668 case KEYWORD_INTERFACE:
669 case KEYWORD_NAMESPACE:
670 case KEYWORD_STRUCT:
671 case KEYWORD_UNION:
672 result = TRUE;
673 break;
675 default: result = FALSE; break;
677 return result;
680 static boolean isContextualStatement (const statementInfo *const st)
682 boolean result = FALSE;
683 if (st != NULL) switch (st->declaration)
685 case DECL_CLASS:
686 case DECL_ENUM:
687 case DECL_INTERFACE:
688 case DECL_STRUCT:
689 case DECL_UNION:
690 result = TRUE;
691 break;
693 default: result = FALSE; break;
695 return result;
698 static boolean isMember (const statementInfo *const st)
700 boolean result;
701 if (isType (st->context, TOKEN_NAME))
702 result = TRUE;
703 else
704 result = (boolean)
705 (st->parent != NULL && isContextualStatement (st->parent));
706 return result;
709 static void initMemberInfo (statementInfo *const st)
711 accessType accessDefault = ACCESS_UNDEFINED;
713 if (st->parent != NULL) switch (st->parent->declaration)
715 case DECL_ENUM:
716 case DECL_NAMESPACE:
717 case DECL_UNION:
718 accessDefault = ACCESS_UNDEFINED;
719 break;
721 case DECL_CLASS:
722 if (isLanguage (Lang_java))
723 accessDefault = ACCESS_DEFAULT;
724 else
725 accessDefault = ACCESS_PRIVATE;
726 break;
728 case DECL_INTERFACE:
729 case DECL_STRUCT:
730 accessDefault = ACCESS_PUBLIC;
731 break;
733 default: break;
735 st->member.accessDefault = accessDefault;
736 st->member.access = accessDefault;
739 static void reinitStatement (statementInfo *const st, const boolean partial)
741 unsigned int i;
743 if (! partial)
745 st->scope = SCOPE_GLOBAL;
746 if (isContextualStatement (st->parent))
747 st->declaration = DECL_BASE;
748 else
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;
757 st->gotArgs = FALSE;
758 st->gotName = FALSE;
759 st->haveQualifyingName = FALSE;
760 st->tokenIndex = 0;
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.
773 if (! partial)
774 initToken (st->blockName);
776 vStringClear (st->parentClasses);
778 /* Init member info.
780 if (! partial)
781 st->member.access = st->member.accessDefault;
784 static void initStatement (statementInfo *const st, statementInfo *const parent)
786 st->parent = parent;
787 initMemberInfo (st);
788 reinitStatement (st, FALSE);
792 * Tag generation functions
794 static cKind cTagKind (const tagType type)
796 cKind result = CK_UNDEFINED;
797 switch (type)
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;
815 return result;
818 static csharpKind csharpTagKind (const tagType type)
820 csharpKind result = CSK_UNDEFINED;
821 switch (type)
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;
838 return result;
841 static javaKind javaTagKind (const tagType type)
843 javaKind result = JK_UNDEFINED;
844 switch (type)
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;
855 return result;
858 static veraKind veraTagKind (const tagType type) {
859 veraKind result = VK_UNDEFINED;
860 switch (type)
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;
877 return result;
880 static const char *tagName (const tagType type)
882 const char* result;
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;
889 else
890 result = CKinds [cTagKind (type)].name;
891 return result;
894 static int tagLetter (const tagType type)
896 int result;
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;
903 else
904 result = CKinds [cTagKind (type)].letter;
905 return result;
908 static boolean includeTag (const tagType type, const boolean isFileScope)
910 boolean result;
911 if (isFileScope && ! Option.include.fileScope)
912 result = FALSE;
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;
919 else
920 result = CKinds [cTagKind (type)].enabled;
921 return result;
924 static tagType declToTagType (const declType declaration)
926 tagType type = TAG_UNDEFINED;
928 switch (declaration)
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;
943 return type;
946 static const char* accessField (const statementInfo *const st)
948 const char* result = NULL;
949 if (isLanguage (Lang_cpp) && st->scope == SCOPE_FRIEND)
950 result = "friend";
951 else if (st->member.access != ACCESS_UNDEFINED)
952 result = accessString (st->member.access);
953 return result;
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.
971 switch (type)
973 default: break;
975 case TAG_FUNCTION:
976 case TAG_METHOD:
977 case TAG_PROTOTYPE:
978 if (vStringLength (Signature) > 0)
979 tag->extensionFields.signature = vStringValue (Signature);
980 case TAG_CLASS:
981 case TAG_ENUM:
982 case TAG_ENUMERATOR:
983 case TAG_EVENT:
984 case TAG_FIELD:
985 case TAG_INTERFACE:
986 case TAG_MEMBER:
987 case TAG_NAMESPACE:
988 case TAG_PROPERTY:
989 case TAG_STRUCT:
990 case TAG_TASK:
991 case TAG_TYPEDEF:
992 case TAG_UNION:
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);
998 else
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);
1017 if (isMember (st))
1019 tag->extensionFields.access = accessField (st);
1021 break;
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))
1028 char *p;
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);
1101 else
1103 /* remove last component (i.e. enumeration name) from scope */
1104 const char* const sc = vStringValue (scope);
1105 const char* colon = strrchr (sc, ':');
1106 if (colon != NULL)
1108 while (*colon == ':' && colon > sc)
1109 --colon;
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);
1118 makeTagEntry (e);
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 ();
1140 tagEntryInfo e;
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);
1153 makeTagEntry (&e);
1154 makeExtraTagEntry (type, &e, scope);
1155 vStringDelete (scope);
1156 vStringDelete (typeRef);
1160 static boolean isValidTypeSpecifier (const declType declaration)
1162 boolean result;
1163 switch (declaration)
1165 case DECL_BASE:
1166 case DECL_CLASS:
1167 case DECL_ENUM:
1168 case DECL_EVENT:
1169 case DECL_STRUCT:
1170 case DECL_UNION:
1171 result = TRUE;
1172 break;
1174 default:
1175 result = FALSE;
1176 break;
1178 return result;
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))
1193 tagType type;
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))
1198 type = TAG_METHOD;
1199 else if (isLanguage (Lang_vera) && st->declaration == DECL_TASK)
1200 type = TAG_TASK;
1201 else
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)
1241 case DECL_CLASS:
1242 case DECL_ENUM:
1243 case DECL_INTERFACE:
1244 case DECL_NAMESPACE:
1245 case DECL_PROGRAM:
1246 case DECL_STRUCT:
1247 case DECL_UNION:
1248 qualifyCompoundTag (st, nameToken);
1249 break;
1250 default: break;
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),
1267 TAG_EVENT);
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);
1282 else
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),
1288 TAG_LOCAL);
1289 else
1290 makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
1291 TAG_VARIABLE);
1297 * Parsing functions
1300 static int skipToOneOf (const char *const chars)
1302 int c;
1304 c = cppGetc ();
1305 while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1306 return c;
1309 /* Skip to the next non-white character.
1311 static int skipToNonWhite (void)
1313 boolean found = FALSE;
1314 int c;
1316 #if 0
1318 c = cppGetc ();
1319 while (isspace (c));
1320 #else
1321 while (1)
1323 c = cppGetc ();
1324 if (isspace (c))
1325 found = TRUE;
1326 else
1327 break;
1329 if (CollectingSignature && found)
1330 vStringPut (Signature, ' ');
1331 #endif
1333 return c;
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)
1341 int c, next;
1343 c = cppGetc ();
1344 next = cppGetc ();
1345 while (c != EOF && (c != '\n' || next != '}'))
1347 c = next;
1348 next = cppGetc ();
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
1357 * "pair").
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 ();
1366 int matchLevel = 1;
1367 int c = '\0';
1369 while (matchLevel > 0 && (c = skipToNonWhite ()) != EOF)
1371 if (CollectingSignature)
1372 vStringPut (Signature, c);
1373 if (c == begin)
1375 ++matchLevel;
1376 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1378 skipToFormattedBraceMatch ();
1379 break;
1382 else if (c == end)
1384 --matchLevel;
1385 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1387 skipToFormattedBraceMatch ();
1388 break;
1392 if (c == EOF)
1394 verbose ("%s: failed to find match for '%c' at line %lu\n",
1395 getInputFileName (), begin, inputLineNumber);
1396 if (braceMatching)
1397 longjmp (Exception, (int) ExceptionBraceFormattingError);
1398 else
1399 longjmp (Exception, (int) ExceptionFormattingError);
1403 static void skipParens (void)
1405 const int c = skipToNonWhite ();
1407 if (c == '(')
1408 skipToMatch ("()");
1409 else
1410 cppUngetc (c);
1413 static void skipBraces (void)
1415 const int c = skipToNonWhite ();
1417 if (c == '{')
1418 skipToMatch ("{}");
1419 else
1420 cppUngetc (c);
1423 static keywordId analyzeKeyword (const char *const name)
1425 const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1426 return id;
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);
1440 else
1441 token->keyword = analyzeKeyword (vStringValue (token->name));
1443 if (token->keyword == KEYWORD_NONE)
1444 token->type = TOKEN_NAME;
1445 else
1446 token->type = TOKEN_KEYWORD;
1448 else
1450 initToken (token);
1451 if (parensToo)
1453 int c = skipToNonWhite ();
1455 if (c == '(')
1456 skipToMatch ("()");
1461 static void readIdentifier (tokenInfo *const token, const int firstChar)
1463 vString *const name = token->name;
1464 int c = firstChar;
1465 boolean first = TRUE;
1467 initToken (token);
1471 vStringPut (name, c);
1472 if (CollectingSignature)
1474 if (!first)
1475 vStringPut (Signature, c);
1476 first = FALSE;
1478 c = cppGetc ();
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;
1489 int c = firstChar;
1491 initToken (token);
1493 while (isident (c) || c == '.')
1495 vStringPut (name, c);
1496 c = cppGetc ();
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;
1509 st->gotName = TRUE;
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;
1518 st->gotName = TRUE;
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 */
1535 else if (c == '(')
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 ();
1543 if (c == '(')
1544 vStringCatS (name, "()");
1546 else
1548 skipToMatch ("()");
1549 c = cppGetc ();
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 */
1560 if (isspace (c))
1561 whiteSpace = TRUE;
1562 else
1564 if (whiteSpace)
1566 vStringPut (name, ' ');
1567 whiteSpace = FALSE;
1569 vStringPut (name, c);
1571 c = cppGetc ();
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);
1581 c = cppGetc ();
1582 } while (isOneOf (c, acceptable));
1583 vStringTerminate (name);
1586 cppUngetc (c);
1588 token->type = TOKEN_NAME;
1589 token->keyword = KEYWORD_NONE;
1590 processName (st);
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)
1604 if (isMember (st))
1606 if (isLanguage (Lang_cpp))
1608 int c = skipToNonWhite ();
1610 if (c == ':')
1611 reinitStatement (st, FALSE);
1612 else
1613 cppUngetc (c);
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 ();
1631 cppUngetc (c);
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 ();
1648 int c;
1652 c = skipToNonWhite ();
1653 if (isident1 (c))
1655 readIdentifier (token, c);
1656 if (isType (token, TOKEN_NAME))
1657 vStringCat (parent->name, token->name);
1658 else
1660 addParentClass (st, parent);
1661 initToken (parent);
1664 else if (c == qualifier)
1665 vStringPut (parent->name, c);
1666 else if (c == '<')
1667 skipToMatch ("<>");
1668 else if (isType (token, TOKEN_NAME))
1670 addParentClass (st, parent);
1671 initToken (parent);
1673 } while (c != '{' && c != EOF);
1674 cppUngetc (c);
1675 deleteToken (parent);
1676 deleteToken (token);
1679 static void skipStatement (statementInfo *const st)
1681 st->declaration = DECL_IGNORE;
1682 skipToOneOf (";");
1685 static void processToken (tokenInfo *const token, statementInfo *const st)
1687 switch (token->keyword) /* is it a reserved word? */
1689 default: break;
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;
1737 case KEYWORD_EVENT:
1738 if (isLanguage (Lang_csharp))
1739 st->declaration = DECL_EVENT;
1740 break;
1742 case KEYWORD_TYPEDEF:
1743 reinitStatement (st, FALSE);
1744 st->scope = SCOPE_TYPEDEF;
1745 break;
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;
1754 break;
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;
1763 break;
1765 case KEYWORD_FOR:
1766 case KEYWORD_IF:
1767 case KEYWORD_SWITCH:
1768 case KEYWORD_WHILE:
1770 int c = skipToNonWhite ();
1771 if (c == '(')
1772 skipToMatch ("()");
1773 break;
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);
1792 deleteToken (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
1801 * mem-initializer:
1802 * [::] [nested-name-spec] class-name (...)
1803 * identifier
1805 static void skipMemIntializerList (tokenInfo *const token)
1807 int c;
1811 c = skipToNonWhite ();
1812 while (isident1 (c) || c == ':')
1814 if (c != ':')
1815 readIdentifier (token, c);
1816 c = skipToNonWhite ();
1818 if (c == '<')
1820 skipToMatch ("<>");
1821 c = skipToNonWhite ();
1823 if (c == '(')
1825 skipToMatch ("()");
1826 c = skipToNonWhite ();
1828 } while (c == ',');
1829 cppUngetc (c);
1832 static void skipMacro (statementInfo *const st)
1834 tokenInfo *const prev2 = prevToken (st, 2);
1836 if (isType (prev2, TOKEN_NAME))
1837 retardToken (st);
1838 skipToMatch ("()");
1841 /* Skips over characters following the parameter list. This will be either
1842 * non-ANSI style function declarations or C++ stuff. Our choices:
1844 * C (K&R):
1845 * int func ();
1846 * int func (one, two) int one; float two; {...}
1847 * C (ANSI):
1848 * int func (int one, float two);
1849 * int func (int one, float two) {...}
1850 * C++:
1851 * int foo (...) [const|volatile] [throw (...)];
1852 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
1853 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
1854 * catch (...) {...}
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 ();
1868 switch (c)
1870 case ')': break;
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;
1877 case '(':
1878 if (elementCount > 0)
1879 ++elementCount;
1880 skipToMatch ("()");
1881 break;
1883 case ';':
1884 if (parameters == 0 || elementCount < 2)
1886 cppUngetc (c);
1887 end = TRUE;
1889 else if (--parameters == 0)
1890 end = TRUE;
1891 break;
1893 default:
1894 if (isident1 (c))
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;
1903 case KEYWORD_CONST:
1904 case KEYWORD_VOLATILE:
1905 if (vStringLength (Signature) > 0)
1907 vStringPut (Signature, ' ');
1908 vStringCat (Signature, token->name);
1910 break;
1912 case KEYWORD_CATCH:
1913 case KEYWORD_CLASS:
1914 case KEYWORD_EXPLICIT:
1915 case KEYWORD_EXTERN:
1916 case KEYWORD_FRIEND:
1917 case KEYWORD_INLINE:
1918 case KEYWORD_MUTABLE:
1919 case KEYWORD_NAMESPACE:
1920 case KEYWORD_NEW:
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:
1931 case KEYWORD_USING:
1932 case KEYWORD_VIRTUAL:
1933 /* Never allowed within parameter declarations. */
1934 restart = TRUE;
1935 end = TRUE;
1936 break;
1938 default:
1939 if (isType (token, TOKEN_NONE))
1941 else if (info->isKnrParamList && info->parameterCount > 0)
1942 ++elementCount;
1943 else
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.
1951 restart = TRUE;
1952 end = TRUE;
1954 break;
1958 if (! end)
1960 c = skipToNonWhite ();
1961 if (c == EOF)
1962 end = TRUE;
1964 } while (! end);
1966 if (restart)
1967 restartStatement (st);
1968 else
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 ();
1979 if (isident1 (c))
1981 readIdentifier (token, c);
1982 if (token->keyword == KEYWORD_THROWS)
1986 c = skipToNonWhite ();
1987 if (isident1 (c))
1989 readIdentifier (token, c);
1990 c = skipToNonWhite ();
1992 } while (c == '.' || c == ',');
1995 cppUngetc (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 ();
2004 cppUngetc (c);
2005 if (isOneOf (c, "{;,="))
2007 else if (isLanguage (Lang_java))
2008 skipJavaThrows (st);
2009 else
2011 if (! skipPostArgumentStuff (st, info))
2013 verbose (
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);
2038 switch (c)
2040 case '&':
2041 case '*':
2042 info->isPointer = TRUE;
2043 info->isKnrParamList = FALSE;
2044 if (identifierCount == 0)
2045 info->isParamList = FALSE;
2046 initToken (token);
2047 break;
2049 case ':':
2050 info->isKnrParamList = FALSE;
2051 break;
2053 case '.':
2054 info->isNameCandidate = FALSE;
2055 c = cppGetc ();
2056 if (c != '.')
2058 cppUngetc (c);
2059 info->isKnrParamList = FALSE;
2061 else
2063 c = cppGetc ();
2064 if (c != '.')
2066 cppUngetc (c);
2067 info->isKnrParamList = FALSE;
2069 else
2070 vStringCatS (Signature, "..."); /* variable arg list */
2072 break;
2074 case ',':
2075 info->isNameCandidate = FALSE;
2076 if (info->isKnrParamList)
2078 ++info->parameterCount;
2079 identifierCount = 0;
2081 break;
2083 case '=':
2084 info->isKnrParamList = FALSE;
2085 info->isNameCandidate = FALSE;
2086 if (firstChar)
2088 info->isParamList = FALSE;
2089 skipMacro (st);
2090 depth = 0;
2092 break;
2094 case '[':
2095 info->isKnrParamList = FALSE;
2096 skipToMatch ("[]");
2097 break;
2099 case '<':
2100 info->isKnrParamList = FALSE;
2101 skipToMatch ("<>");
2102 break;
2104 case ')':
2105 if (firstChar)
2106 info->parameterCount = 0;
2107 --depth;
2108 break;
2110 case '(':
2111 info->isKnrParamList = FALSE;
2112 if (firstChar)
2114 info->isNameCandidate = FALSE;
2115 cppUngetc (c);
2116 vStringClear (Signature);
2117 skipMacro (st);
2118 depth = 0;
2119 vStringChop (Signature);
2121 else if (isType (token, TOKEN_PAREN_NAME))
2123 c = skipToNonWhite ();
2124 if (c == '*') /* check for function pointer */
2126 skipToMatch ("()");
2127 c = skipToNonWhite ();
2128 if (c == '(')
2129 skipToMatch ("()");
2130 else
2131 cppUngetc (c);
2133 else
2135 cppUngetc (c);
2136 cppUngetc ('(');
2137 info->nestedArgs = TRUE;
2140 else
2141 ++depth;
2142 break;
2144 default:
2145 if (isident1 (c))
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;
2162 else
2164 info->isParamList = FALSE;
2165 info->isKnrParamList = FALSE;
2166 info->isNameCandidate = FALSE;
2167 info->invalidContents = TRUE;
2169 break;
2171 firstChar = FALSE;
2172 } while (! info->nestedArgs && depth > 0 &&
2173 (info->isKnrParamList || info->isNameCandidate));
2175 if (! info->nestedArgs) while (depth > 0)
2177 skipToMatch ("()");
2178 --depth;
2181 if (! info->isNameCandidate)
2182 initToken (token);
2184 vStringTerminate (Signature);
2185 if (info->isKnrParamList)
2186 vStringClear (Signature);
2187 CollectingSignature = FALSE;
2188 return nextChar;
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);
2211 parenInfo info;
2212 int c;
2214 initParenInfo (&info);
2215 parseParens (st, &info);
2216 c = skipToNonWhite ();
2217 cppUngetc (c);
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 ||
2223 c == '(' ||
2224 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2225 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2227 token->type = TOKEN_NAME;
2228 processName (st);
2229 st->gotParenName = TRUE;
2230 if (! (c == '(' && info.nestedArgs))
2231 st->isPointer = info.isPointer;
2233 else if (! st->gotArgs && info.isParamList)
2235 st->gotArgs = TRUE;
2236 setToken (st, TOKEN_ARGS);
2237 advanceToken (st);
2238 if (st->scope != SCOPE_TYPEDEF)
2239 analyzePostParens (st, &info);
2241 else
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)
2268 return (boolean) (
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 == ':');
2279 if (doubleColon)
2281 setToken (st, TOKEN_DOUBLE_COLON);
2282 st->haveQualifyingName = FALSE;
2284 else
2286 cppUngetc (c);
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 (",;");
2295 if (c == ',')
2296 setToken (st, TOKEN_COMMA);
2297 else if (c == ';')
2298 setToken (st, TOKEN_SEMICOLON);
2300 else
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 ||
2306 st->parent != NULL)
2308 reinitStatement (st, FALSE);
2314 static void processAngleBracket (void)
2316 int c = cppGetc ();
2317 if (c == '>')
2318 ; /* already found match for template */
2319 else if ((isLanguage (Lang_cpp) || isLanguage (Lang_java)) &&
2320 c != '<' && c != '=')
2322 skipToMatch ("<>"); /* this is a template */
2324 else
2325 cppUngetc (c);
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;
2334 int c;
2336 while (! done)
2338 c = skipToNonWhite ();
2340 if (c == EOF)
2341 longjmp (Exception, (int) ExceptionFormattingError);
2342 else switch (c)
2344 case ',':
2345 case ';': done = TRUE; break;
2347 case '0':
2348 if (st->implementation == IMP_VIRTUAL)
2349 st->implementation = IMP_PURE_VIRTUAL;
2350 break;
2352 case '[': skipToMatch ("[]"); break;
2353 case '(': skipToMatch ("()"); break;
2354 case '{': skipToMatch ("{}"); break;
2356 case '}':
2357 if (insideEnumBody (st))
2358 done = TRUE;
2359 else if (! isBraceFormat ())
2361 verbose ("%s: unexpected closing brace at line %lu\n",
2362 getInputFileName (), getInputLineNumber ());
2363 longjmp (Exception, (int) ExceptionBraceFormattingError);
2365 break;
2367 default: break;
2370 return c;
2373 static void processInitializer (statementInfo *const st)
2375 const boolean inEnumBody = insideEnumBody (st);
2376 int c = cppGetc ();
2378 if (c != '=')
2380 cppUngetc (c);
2381 c = skipInitializer (st);
2382 st->assignment = TRUE;
2383 if (c == ';')
2384 setToken (st, TOKEN_SEMICOLON);
2385 else if (c == ',')
2386 setToken (st, TOKEN_COMMA);
2387 else if ('}' && inEnumBody)
2389 cppUngetc (c);
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;
2423 if (c == '-')
2425 int c2 = cppGetc ();
2426 if (c2 != '>')
2427 cppUngetc (c2);
2430 else if (c == '!' || c == '>')
2432 int c2 = cppGetc ();
2433 if (c2 != '=')
2434 cppUngetc (c2);
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)
2448 tokenInfo *token;
2451 int c = skipToNonWhite ();
2452 switch (c)
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);
2480 unsigned int i;
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;
2492 return st;
2495 static void deleteStatement (void)
2497 statementInfo *const st = CurrentStatement;
2498 statementInfo *const parent = st->parent;
2499 unsigned int i;
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;
2508 eFree (st);
2509 CurrentStatement = parent;
2512 static void deleteAllStatements (void)
2514 while (CurrentStatement != NULL)
2515 deleteStatement ();
2518 static boolean isStatementEnd (const statementInfo *const st)
2520 const tokenInfo *const token = activeToken (st);
2521 boolean isEnd;
2523 if (isType (token, TOKEN_SEMICOLON))
2524 isEnd = TRUE;
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));
2531 else
2532 isEnd = FALSE;
2534 return isEnd;
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);
2547 cppEndStatement ();
2549 else
2551 cppBeginStatement ();
2552 advanceToken (st);
2556 static void nest (statementInfo *const st, const unsigned int nestLevel)
2558 switch (st->declaration)
2560 case DECL_CLASS:
2561 case DECL_ENUM:
2562 case DECL_INTERFACE:
2563 case DECL_NAMESPACE:
2564 case DECL_NOMANGLE:
2565 case DECL_STRUCT:
2566 case DECL_UNION:
2567 createTags (nestLevel, st);
2568 break;
2570 case DECL_FUNCTION:
2571 case DECL_TASK:
2572 st->inFunction = TRUE;
2573 /* fall through */
2574 default:
2575 if (includeTag (TAG_LOCAL, FALSE))
2576 createTags (nestLevel, st);
2577 else
2578 skipToMatch ("{}");
2579 break;
2581 advanceToken (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)
2593 case TOKEN_NAME:
2594 if (insideEnumBody (st))
2595 qualifyEnumeratorTag (st, token);
2596 break;
2597 #if 0
2598 case TOKEN_PACKAGE:
2599 if (st->haveQualifyingName)
2600 makeTag (token, st, FALSE, TAG_PACKAGE);
2601 break;
2602 #endif
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);
2621 else
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);
2636 break;
2638 case TOKEN_SEMICOLON:
2639 case TOKEN_COMMA:
2640 if (insideEnumBody (st))
2642 else if (isType (prev, TOKEN_NAME))
2644 if (isContextualKeyword (prev2))
2645 st->scope = SCOPE_EXTERN;
2646 else
2647 qualifyVariableTag (st, prev);
2649 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
2651 if (st->isPointer)
2652 qualifyVariableTag (st, prev2);
2653 else
2654 qualifyFunctionDeclTag (st, prev2);
2656 break;
2658 default: break;
2662 /* Parses the current file and decides whether to write out and tags that
2663 * are discovered.
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); )
2671 while (TRUE)
2673 tokenInfo *token;
2675 nextToken (st);
2676 token = activeToken (st);
2677 if (isType (token, TOKEN_BRACE_CLOSE))
2679 if (nestLevel > 0)
2680 break;
2681 else
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));
2691 advanceToken (st);
2693 else
2695 tagCheck (st);
2696 if (isType (token, TOKEN_BRACE_OPEN))
2697 nest (st, nestLevel + 1);
2698 checkStatementEnd (st);
2701 deleteStatement ();
2702 DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
2705 static boolean findCTags (const unsigned int passCount)
2707 exception_t exception;
2708 boolean retry;
2710 Assert (passCount < 3);
2711 cppInit ((boolean) (passCount > 1));
2712 Signature = vStringNew ();
2714 exception = (exception_t) setjmp (Exception);
2715 retry = FALSE;
2716 if (exception == ExceptionNone)
2717 createTags (0, NULL);
2718 else
2720 deleteAllStatements ();
2721 if (exception == ExceptionBraceFormattingError && passCount == 1)
2723 retry = TRUE;
2724 verbose ("%s: retrying file with fallback brace matching algorithm\n",
2725 getInputFileName ());
2728 vStringDelete (Signature);
2729 cppTerminate ();
2730 return retry;
2733 static void buildKeywordHash (const langType language, unsigned int idx)
2735 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
2736 size_t i;
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)
2747 Lang_c = 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;
2784 return def;
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
2792 "C", "H",
2793 #endif
2794 NULL
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;
2802 return def;
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;
2814 return def;
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;
2826 return def;
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;
2838 return def;
2841 /* vi:set tabstop=4 shiftwidth=4 noexpandtab: */