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