Remove duplicate NEWS item
[geany-mirror.git] / tagmanager / c.c
blobb55581098432c55782956196a4aaad7ed6480202
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>
19 #include <mio/mio.h>
21 #include "entry.h"
22 #include "get.h"
23 #include "keyword.h"
24 #include "main.h"
25 #include "options.h"
26 #include "parse.h"
27 #include "read.h"
30 * MACROS
33 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
34 #define parentDecl(st) ((st)->parent == NULL ? \
35 DECL_NONE : (st)->parent->declaration)
36 #define isType(token,t) (boolean) ((token)->type == (t))
37 #define insideEnumBody(st) (boolean) ((st)->parent == NULL ? FALSE : \
38 ((st)->parent->declaration == DECL_ENUM))
39 #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
40 ! (st)->haveQualifyingName && \
41 (st)->scope == SCOPE_EXTERN)
43 #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
46 * DATA DECLARATIONS
49 enum { NumTokens = 12 };
51 typedef enum eException
53 ExceptionNone, ExceptionEOF, ExceptionFormattingError,
54 ExceptionBraceFormattingError
55 } exception_t;
57 /* Used to specify type of keyword.
59 typedef enum eKeywordId
61 KEYWORD_NONE = -1,
62 KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT, KEYWORD_ALIAS,
63 KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
64 KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT, KEYWORD_BODY,
65 KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
66 KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
67 KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
68 KEYWORD_DOUBLE,
69 KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
70 KEYWORD_EXTENDS, KEYWORD_EVENT,
71 KEYWORD_FINAL, KEYWORD_FINALLY, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FRIEND, KEYWORD_FUNCTION,
72 KEYWORD_GET, KEYWORD_GOTO,
73 KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_IN, KEYWORD_INLINE, KEYWORD_INT,
74 KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
75 KEYWORD_INTERNAL,
76 KEYWORD_LOCAL, KEYWORD_LONG,
77 KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
78 KEYWORD_MODULE, KEYWORD_MUTABLE,
79 KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE,
80 KEYWORD_OPERATOR, KEYWORD_OUT, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
81 KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE,
82 KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
83 KEYWORD_REF, KEYWORD_REGISTER, KEYWORD_RETURN,
84 KEYWORD_SHADOW, KEYWORD_STATE,
85 KEYWORD_SET, KEYWORD_SHORT, KEYWORD_SIGNAL, KEYWORD_SIGNED, KEYWORD_SIZE_T, KEYWORD_STATIC, KEYWORD_STRING,
86 KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
87 KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
88 KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
89 KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
90 KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
91 KEYWORD_USING,
92 KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
93 KEYWORD_WCHAR_T, KEYWORD_WEAK, KEYWORD_WHILE
94 } keywordId;
96 /* Used to determine whether keyword is valid for the current language and
97 * what its ID is.
99 typedef struct sKeywordDesc
101 const char *name;
102 keywordId id;
103 short isValid [7]; /* indicates languages for which kw is valid */
104 } keywordDesc;
106 /* Used for reporting the type of object parsed by nextToken ().
108 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_COMMA, /* the comma character */
115 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
116 TOKEN_KEYWORD,
117 TOKEN_NAME, /* an unknown name */
118 TOKEN_PACKAGE, /* a Java package name */
119 TOKEN_PAREN_NAME, /* a single name in parentheses */
120 TOKEN_SEMICOLON, /* the semicolon character */
121 TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
122 TOKEN_STAR, /* pointer detection */
123 TOKEN_ARRAY, /* array detection */
124 TOKEN_COUNT
125 } tokenType;
127 /* This describes the scoping of the current statement.
129 typedef enum eTagScope
131 SCOPE_GLOBAL, /* no storage class specified */
132 SCOPE_STATIC, /* static storage class */
133 SCOPE_EXTERN, /* external storage class */
134 SCOPE_FRIEND, /* declares access only */
135 SCOPE_TYPEDEF, /* scoping depends upon context */
136 SCOPE_COUNT
137 } tagScope;
139 typedef enum eDeclaration
141 DECL_NONE,
142 DECL_BASE, /* base type (default) */
143 DECL_CLASS,
144 DECL_ENUM,
145 DECL_EVENT,
146 DECL_SIGNAL,
147 DECL_FUNCTION,
148 DECL_FUNCTION_TEMPLATE,
149 DECL_IGNORE, /* non-taggable "declaration" */
150 DECL_INTERFACE,
151 DECL_MODULE,
152 DECL_NAMESPACE,
153 DECL_NOMANGLE, /* C++ name demangling block */
154 DECL_PACKAGE,
155 DECL_STRUCT,
156 DECL_UNION,
157 DECL_COUNT
158 } declType;
160 typedef enum eVisibilityType
162 ACCESS_UNDEFINED,
163 ACCESS_PRIVATE,
164 ACCESS_PROTECTED,
165 ACCESS_PUBLIC,
166 ACCESS_DEFAULT, /* Java-specific */
167 ACCESS_COUNT
168 } accessType;
170 /* Information about the parent class of a member (if any).
172 typedef struct sMemberInfo
174 accessType access; /* access of current statement */
175 accessType accessDefault; /* access default for current statement */
176 } memberInfo;
178 typedef struct sTokenInfo
180 tokenType type;
181 keywordId keyword;
182 vString* name; /* the name of the token */
183 unsigned long lineNumber; /* line number of tag */
184 MIOPos filePosition; /* file position of line containing name */
185 } tokenInfo;
187 typedef enum eImplementation
189 IMP_DEFAULT,
190 IMP_ABSTRACT,
191 IMP_VIRTUAL,
192 IMP_PURE_VIRTUAL,
193 IMP_COUNT
194 } impType;
196 /* Describes the statement currently undergoing analysis.
198 typedef struct sStatementInfo
200 tagScope scope;
201 declType declaration; /* specifier associated with TOKEN_SPEC */
202 boolean gotName; /* was a name parsed yet? */
203 boolean haveQualifyingName; /* do we have a name we are considering? */
204 boolean gotParenName; /* was a name inside parentheses parsed yet? */
205 boolean gotArgs; /* was a list of parameters parsed yet? */
206 impType implementation; /* abstract or concrete implementation? */
207 unsigned int tokenIndex; /* currently active token */
208 tokenInfo* token [((int) NumTokens)];
209 tokenInfo* context; /* accumulated scope of current statement */
210 tokenInfo* blockName; /* name of current block */
211 memberInfo member; /* information regarding parent class/struct */
212 vString* parentClasses; /* parent classes */
213 struct sStatementInfo *parent; /* statement we are nested within */
214 long argEndPosition; /* Position where argument list ended */
215 tokenInfo* firstToken; /* First token in the statement */
216 } statementInfo;
218 /* Describes the type of tag being generated.
220 typedef enum eTagType
222 TAG_UNDEFINED,
223 TAG_CLASS, /* class name */
224 TAG_ENUM, /* enumeration name */
225 TAG_ENUMERATOR, /* enumerator (enumeration value) */
226 TAG_FIELD, /* field (Java) */
227 TAG_FUNCTION, /* function definition */
228 TAG_INTERFACE, /* interface declaration */
229 TAG_MEMBER, /* structure, class or interface member */
230 TAG_METHOD, /* method declaration */
231 TAG_NAMESPACE, /* namespace name */
232 TAG_PACKAGE, /* package name */
233 TAG_PROTOTYPE, /* function prototype or declaration */
234 TAG_STRUCT, /* structure name */
235 TAG_TYPEDEF, /* typedef name */
236 TAG_UNION, /* union name */
237 TAG_VARIABLE, /* variable definition */
238 TAG_EXTERN_VAR, /* external variable declaration */
239 TAG_MACRO, /* #define s */
240 TAG_EVENT, /* event */
241 TAG_SIGNAL, /* signal */
242 TAG_LOCAL, /* local variable definition */
243 TAG_PROPERTY, /* property name */
244 TAG_COUNT /* must be last */
245 } tagType;
247 typedef struct sParenInfo
249 boolean isParamList;
250 boolean isKnrParamList;
251 boolean isNameCandidate;
252 boolean invalidContents;
253 boolean nestedArgs;
254 unsigned int parameterCount;
255 } parenInfo;
258 * DATA DEFINITIONS
261 static jmp_buf Exception;
263 static langType Lang_c;
264 static langType Lang_cpp;
265 static langType Lang_csharp;
266 static langType Lang_java;
267 static langType Lang_d;
268 static langType Lang_glsl;
269 static langType Lang_ferite;
270 static langType Lang_vala;
272 /* Used to index into the CKinds table. */
273 typedef enum
275 CK_UNDEFINED = -1,
276 CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
277 CK_ENUMERATION, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
278 CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
279 CK_EXTERN_VARIABLE
280 } cKind;
282 static kindOption CKinds [] = {
283 { TRUE, 'c', "class", "classes"},
284 { TRUE, 'd', "macro", "macro definitions"},
285 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
286 { TRUE, 'f', "function", "function definitions"},
287 { TRUE, 'g', "enum", "enumeration names"},
288 { TRUE, 'm', "member", "class, struct, and union members"},
289 { TRUE, 'n', "namespace", "namespaces"},
290 { FALSE, 'p', "prototype", "function prototypes"},
291 { TRUE, 's', "struct", "structure names"},
292 { TRUE, 't', "typedef", "typedefs"},
293 { TRUE, 'u', "union", "union names"},
294 { TRUE, 'v', "variable", "variable definitions"},
295 { FALSE, 'x', "externvar", "external variable declarations"},
298 /* Used to index into the DKinds table. */
299 typedef enum
301 DK_UNDEFINED = -1,
302 DK_CLASS, DK_ENUMERATOR, DK_FUNCTION,
303 DK_ENUMERATION, DK_INTERFACE, DK_MEMBER, DK_NAMESPACE, DK_PROTOTYPE,
304 DK_STRUCT, DK_TYPEDEF, DK_UNION, DK_VARIABLE,
305 DK_EXTERN_VARIABLE
306 } dKind;
308 static kindOption DKinds [] = {
309 { TRUE, 'c', "class", "classes"},
310 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
311 { TRUE, 'f', "function", "function definitions"},
312 { TRUE, 'g', "enum", "enumeration names"},
313 { TRUE, 'i', "interface", "interfaces"},
314 { TRUE, 'm', "member", "class, struct, and union members"},
315 { TRUE, 'n', "namespace", "namespaces"},
316 { FALSE, 'p', "prototype", "function prototypes"},
317 { TRUE, 's', "struct", "structure names"},
318 { TRUE, 't', "typedef", "typedefs"},
319 { TRUE, 'u', "union", "union names"},
320 { TRUE, 'v', "variable", "variable definitions"},
321 { FALSE, 'x', "externvar", "external variable declarations"},
324 /* Used to index into the JavaKinds table. */
325 typedef enum
327 JK_UNDEFINED = -1,
328 JK_CLASS, JK_FIELD, JK_INTERFACE, JK_METHOD,
329 JK_PACKAGE
330 } javaKind;
332 static kindOption JavaKinds [] = {
333 { TRUE, 'c', "class", "classes"},
334 { TRUE, 'f', "field", "fields"},
335 { TRUE, 'i', "interface", "interfaces"},
336 { TRUE, 'm', "method", "methods"},
337 { TRUE, 'p', "package", "packages"},
340 typedef enum
342 CSK_UNDEFINED = -1,
343 CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
344 CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
345 CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
346 } csharpKind;
348 static kindOption CsharpKinds [] = {
349 { TRUE, 'c', "class", "classes"},
350 { TRUE, 'd', "macro", "macro definitions"},
351 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
352 { TRUE, 'E', "event", "events"},
353 { TRUE, 'f', "field", "fields"},
354 { TRUE, 'g', "enum", "enumeration names"},
355 { TRUE, 'i', "interface", "interfaces"},
356 { FALSE, 'l', "local", "local variables"},
357 { TRUE, 'm', "method", "methods"},
358 { TRUE, 'n', "namespace", "namespaces"},
359 { TRUE, 'p', "property", "properties"},
360 { TRUE, 's', "struct", "structure names"},
361 { TRUE, 't', "typedef", "typedefs"},
364 typedef enum {
365 VK_UNDEFINED = -1,
366 VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FIELD,
367 VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_METHOD,
368 VK_NAMESPACE, VK_PROPERTY, VK_SIGNAL, VK_STRUCT
369 } valaKind;
371 static kindOption ValaKinds [] = {
372 { TRUE, 'c', "class", "classes"},
373 { TRUE, 'd', "macro", "macro definitions"},
374 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
375 { TRUE, 'f', "field", "fields"},
376 { TRUE, 'g', "enum", "enumeration names"},
377 { TRUE, 'i', "interface", "interfaces"},
378 { FALSE, 'l', "local", "local variables"},
379 { TRUE, 'm', "method", "methods"},
380 { TRUE, 'n', "namespace", "namespaces"},
381 { TRUE, 'p', "property", "properties"},
382 { TRUE, 'S', "signal", "signals"},
383 { TRUE, 's', "struct", "structure names"},
386 static const keywordDesc KeywordTable [] = {
387 /* C++ */
388 /* ANSI C | C# Java */
389 /* | | | | Vera */
390 /* | | | | | Vala */
391 /* | | | | | | D */
392 /* keyword keyword ID | | | | | | | */
393 { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0, 0, 1 } },
394 { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0, 1, 1 } },
395 { "alias", KEYWORD_TYPEDEF, { 0, 0, 0, 0, 0, 0, 1 } }, /* handle like typedef */
396 { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
397 { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
398 { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1, 0, 0 } },
399 { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1, 0, 0 } },
400 { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1, 0, 0 } },
401 { "body", KEYWORD_BODY, { 0, 0, 0, 0, 0, 0, 1 } },
402 { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0, 0, 0 } },
403 { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0, 0, 1 } },
404 { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0, 1, 1 } },
405 { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0, 1, 1 } },
406 { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0, 1, 1 } },
407 { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1, 1, 1 } },
408 { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0, 1, 1 } },
409 { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1, 0, 0 } },
410 { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1, 0, 0 } },
411 { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1, 0, 0 } },
412 { "do", KEYWORD_DO, { 1, 1, 1, 1, 0, 1, 1 } },
413 { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0, 1, 1 } },
414 { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0, 1, 1 } },
415 { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0, 1, 1 } },
416 { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0, 1, 1 } },
417 { "else", KEYWORD_ELSE, { 1, 1, 0, 1, 0, 1, 1 } },
418 { "ensures", KEYWORD_ATTRIBUTE, { 0, 0, 0, 0, 0, 1, 0 } }, /* ignore */
419 { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1, 1, 1 } },
420 { "errordomain", KEYWORD_ENUM, { 0, 0, 0, 0, 0, 1, 0 } }, /* errordomain behaves like enum */
421 { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1, 0, 0 } },
422 { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0, 0, 1 } },
423 { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1, 0, 0 } },
424 { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1, 1, 0 } },
425 { "extern", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
426 { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0, 0, 1 } },
427 { "finally", KEYWORD_FINALLY, { 0, 0, 0, 0, 0, 1, 1 } },
428 { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0, 1, 1 } },
429 { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0, 1, 1 } },
430 { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0, 0, 0 } },
431 { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1, 0, 1 } },
432 { "get", KEYWORD_GET, { 0, 0, 0, 0, 0, 1, 0 } },
433 { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0, 1, 1 } },
434 { "if", KEYWORD_IF, { 1, 1, 1, 1, 0, 1, 1 } },
435 { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0, 0, 0 } },
436 { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0, 0, 1 } },
437 { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0, 1, 0 } },
438 { "in", KEYWORD_IN, { 0, 0, 0, 0, 0, 0, 1 } },
439 { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1, 0, 1 } },
440 { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1, 0, 0 } },
441 { "int", KEYWORD_INT, { 1, 1, 1, 1, 0, 1, 1 } },
442 { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1, 0, 0 } },
443 { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1, 1, 1 } },
444 { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0, 0, 0 } },
445 { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1, 0, 0 } },
446 { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0, 1, 1 } },
447 { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
448 { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
449 { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
450 { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
451 { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0, 0, 0 } },
452 { "module", KEYWORD_MODULE, { 0, 0, 0, 0, 0, 0, 1 } },
453 { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0, 1, 0 } },
454 { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0, 0, 0 } },
455 { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0, 1, 1 } },
456 { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1, 0, 0 } },
457 { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0, 0, 0 } },
458 { "out", KEYWORD_OUT, { 0, 0, 0, 0, 0, 1, 1 } },
459 { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1, 0, 0 } },
460 { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0, 0, 0 } },
461 { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0, 1, 1 } },
462 { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0, 0, 1 } },
463 { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1, 0, 0 } },
464 { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1, 0, 0 } },
465 { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0, 1, 1 } },
466 { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1, 0, 0 } },
467 { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1, 1, 1 } },
468 { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1, 1, 1 } },
469 { "ref", KEYWORD_REF, { 0, 0, 0, 0, 0, 1, 1 } },
470 { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0, 0, 0 } },
471 { "requires", KEYWORD_ATTRIBUTE, { 0, 0, 0, 0, 0, 1, 0 } }, /* ignore */
472 { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0, 1, 1 } },
473 { "set", KEYWORD_SET, { 0, 0, 0, 0, 0, 1, 0 } },
474 { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1, 0, 0 } },
475 { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0, 1, 1 } },
476 { "signal", KEYWORD_SIGNAL, { 0, 0, 0, 0, 0, 1, 0 } },
477 { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0, 0, 0 } },
478 { "size_t", KEYWORD_SIZE_T, { 1, 1, 0, 0, 0, 1, 1 } },
479 { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
480 { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1, 1, 1 } },
481 { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1, 1, 0 } },
482 { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0, 1, 1 } },
483 { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0, 1, 1 } },
484 { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0, 0, 1 } },
485 { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1, 0, 0 } },
486 { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0, 0, 0 } },
487 { "template", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
488 { "this", KEYWORD_THIS, { 0, 0, 1, 1, 0, 1, 0 } }, /* 0 to allow D ctor tags */
489 { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0, 1, 1 } },
490 { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0, 1, 0 } },
491 { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
492 { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1, 0, 0 } },
493 { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0, 0, 0 } },
494 { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0, 1, 1 } },
495 { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1, 0, 1 } },
496 { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0, 0, 0 } },
497 { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0, 1, 1 } },
498 { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0, 1, 1 } },
499 { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0, 0, 1 } },
500 { "unittest", KEYWORD_BODY, { 0, 0, 0, 0, 0, 0, 1 } }, /* ignore */
501 { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0, 0, 1 } },
502 { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0, 1, 1 } },
503 { "using", KEYWORD_USING, { 0, 1, 1, 0, 0, 1, 0 } },
504 { "version", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
505 { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1, 1, 0 } },
506 { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1, 1, 1 } },
507 { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0, 0, 1 } },
508 { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0, 0, 1 } },
509 { "weak", KEYWORD_WEAK, { 0, 0, 0, 0, 0, 1, 0 } },
510 { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0, 1, 1 } }
515 * FUNCTION PROTOTYPES
517 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
518 static void copyToken (tokenInfo *const dest, const tokenInfo *const src);
519 static const char *getVarType (const statementInfo *const st);
522 * FUNCTION DEFINITIONS
525 /* Debugging functions added by Biswa */
526 #if defined(DEBUG_C) && DEBUG_C
527 static char *tokenTypeName[] = {
528 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
529 "package", "paren-name", "';'", "spec", "*", "[]", "count"
532 static char *tagScopeNames[] = {
533 "global", "static", "extern", "friend", "typedef", "count"};
535 static char *declTypeNames[] = {
536 "none", "base", "class", "enum", "function", "ignore", "interface",
537 "namespace", "nomangle", "package", "struct", "union", "count"};
539 static char *impTypeNames[] = {
540 "default", "abstract", "virtual", "pure-virtual", "count"};
542 void printToken(const tokenInfo *const token)
544 fprintf(stderr, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName[token->type],
545 token->keyword, vStringValue(token->name));
548 void printTagEntry(const tagEntryInfo *tag)
550 fprintf(stderr, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag->name,
551 tag->kindName, tag->extensionFields.implementation, tag->extensionFields.scope[1],
552 tag->extensionFields.varType);
555 void printStatement(const statementInfo *const statement)
557 int i;
558 statementInfo *st = (statementInfo *) statement;
559 while (NULL != st)
561 fprintf(stderr, "Statement Info:\n------------------------\n");
562 fprintf(stderr, "scope: %s, decl: %s, impl: %s\n", tagScopeNames[st->scope],
563 declTypeNames[st->declaration], impTypeNames[st->implementation]);
564 for (i=0; i < NumTokens; ++i)
566 fprintf(stderr, "Token %d %s: ", i, (i == st->tokenIndex)?"(current)":"");
567 printToken(st->token[i]);
569 fprintf(stderr, "Context: ");
570 printToken(st->context);
571 fprintf(stderr, "Block: ");
572 printToken(st->blockName);
573 fprintf(stderr, "Parent classes: %s\n", vStringValue(st->parentClasses));
574 fprintf(stderr, "First token: ");
575 printToken(st->firstToken);
576 if (NULL != st->parent)
577 fprintf(stderr, "Printing Parent:\n");
578 st = st->parent;
580 fprintf(stderr, "-----------------------------------------------\n");
582 #endif
584 extern boolean includingDefineTags (void)
586 if (isLanguage(Lang_c) ||
587 isLanguage(Lang_cpp) ||
588 isLanguage(Lang_csharp) ||
589 isLanguage(Lang_ferite) ||
590 isLanguage(Lang_glsl) ||
591 isLanguage(Lang_vala))
592 return CKinds [CK_DEFINE].enabled;
594 return FALSE;
598 * Token management
601 static void initToken (tokenInfo* const token)
603 token->type = TOKEN_NONE;
604 token->keyword = KEYWORD_NONE;
605 token->lineNumber = getSourceLineNumber();
606 token->filePosition = getInputFilePosition();
607 vStringClear(token->name);
610 static void advanceToken (statementInfo* const st)
612 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
613 st->tokenIndex = 0;
614 else
615 ++st->tokenIndex;
616 initToken(st->token[st->tokenIndex]);
619 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
621 unsigned int tokenIndex;
622 unsigned int num = (unsigned int) NumTokens;
623 Assert(n < num);
624 tokenIndex = (st->tokenIndex + num - n) % num;
626 return st->token[tokenIndex];
629 static void setToken (statementInfo *const st, const tokenType type)
631 tokenInfo *token;
632 token = activeToken (st);
633 initToken(token);
634 token->type = type;
637 static void retardToken (statementInfo *const st)
639 if (st->tokenIndex == 0)
640 st->tokenIndex = (unsigned int) NumTokens - 1;
641 else
642 --st->tokenIndex;
643 setToken(st, TOKEN_NONE);
646 static tokenInfo *newToken (void)
648 tokenInfo *const token = xMalloc (1, tokenInfo);
649 token->name = vStringNew();
650 initToken(token);
651 return token;
654 static void deleteToken (tokenInfo *const token)
656 if (token != NULL)
658 vStringDelete(token->name);
659 eFree(token);
663 static const char *accessString (const accessType laccess)
665 static const char *const names [] = {
666 "?", "private", "protected", "public", "default"
668 Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
669 Assert ((int) laccess < ACCESS_COUNT);
670 return names[(int) laccess];
673 static const char *implementationString (const impType imp)
675 static const char *const names [] = {
676 "?", "abstract", "virtual", "pure virtual"
678 Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
679 Assert ((int) imp < IMP_COUNT);
680 return names [(int) imp];
684 * Debugging functions
687 #ifdef TM_DEBUG
689 #define boolString(c) ((c) ? "TRUE" : "FALSE")
691 static const char *tokenString (const tokenType type)
693 static const char *const names [] = {
694 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
695 "package", "paren-name", "semicolon", "specifier", "*", "[]"
697 Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
698 Assert ((int) type < TOKEN_COUNT);
699 return names[(int) type];
702 static const char *scopeString (const tagScope scope)
704 static const char *const names [] = {
705 "global", "static", "extern", "friend", "typedef"
707 Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
708 Assert ((int) scope < SCOPE_COUNT);
709 return names[(int) scope];
712 static const char *declString (const declType declaration)
714 static const char *const names [] = {
715 "?", "base", "class", "enum", "event", "signal", "function",
716 "function template", "ignore", "interface", "module", "namespace",
717 "no mangle", "package", "struct", "union",
719 Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
720 Assert ((int) declaration < DECL_COUNT);
721 return names[(int) declaration];
724 static const char *keywordString (const keywordId keyword)
726 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
727 const char *name = "none";
728 size_t i;
729 for (i = 0 ; i < count ; ++i)
731 const keywordDesc *p = &KeywordTable[i];
733 if (p->id == keyword)
735 name = p->name;
736 break;
739 return name;
742 static void __unused__ pt (tokenInfo *const token)
744 if (isType (token, TOKEN_NAME))
745 printf("type: %-12s: %-13s line: %lu\n",
746 tokenString (token->type), vStringValue (token->name),
747 token->lineNumber);
748 else if (isType (token, TOKEN_KEYWORD))
749 printf("type: %-12s: %-13s line: %lu\n",
750 tokenString (token->type), keywordString (token->keyword),
751 token->lineNumber);
752 else
753 printf("type: %-12s line: %lu\n",
754 tokenString (token->type), token->lineNumber);
757 static void __unused__ ps (statementInfo *const st)
759 unsigned int i;
760 printf("scope: %s decl: %s gotName: %s gotParenName: %s\n",
761 scopeString (st->scope), declString (st->declaration),
762 boolString (st->gotName), boolString (st->gotParenName));
763 printf("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
764 printf("access: %s default: %s\n", accessString (st->member.access),
765 accessString (st->member.accessDefault));
766 printf("token : ");
767 pt(activeToken (st));
768 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
770 printf("prev %u : ", i);
771 pt(prevToken (st, i));
773 printf("context: ");
774 pt(st->context);
777 #endif
780 * Statement management
783 static boolean isDataTypeKeyword (const tokenInfo *const token)
785 switch (token->keyword)
787 case KEYWORD_BOOLEAN:
788 case KEYWORD_BYTE:
789 case KEYWORD_CHAR:
790 case KEYWORD_DOUBLE:
791 case KEYWORD_FLOAT:
792 case KEYWORD_INT:
793 case KEYWORD_LONG:
794 case KEYWORD_SHORT:
795 case KEYWORD_VOID:
796 case KEYWORD_WCHAR_T:
797 case KEYWORD_SIZE_T:
798 return TRUE;
799 default:
800 return FALSE;
804 #if 0
805 static boolean isVariableKeyword (const tokenInfo *const token)
807 switch (token->keyword)
809 case KEYWORD_CONST:
810 case KEYWORD_EXTERN:
811 case KEYWORD_REGISTER:
812 case KEYWORD_STATIC:
813 case KEYWORD_VIRTUAL:
814 case KEYWORD_SIGNED:
815 case KEYWORD_UNSIGNED:
816 return TRUE;
817 default:
818 return FALSE;
821 #endif
823 static boolean isContextualKeyword (const tokenInfo *const token)
825 boolean result;
826 switch (token->keyword)
828 case KEYWORD_CLASS:
829 case KEYWORD_ENUM:
830 case KEYWORD_INTERFACE:
831 case KEYWORD_NAMESPACE:
832 case KEYWORD_STRUCT:
833 case KEYWORD_UNION:
835 result = TRUE;
836 break;
839 default:
841 result = FALSE;
842 break;
845 return result;
848 static boolean isContextualStatement (const statementInfo *const st)
850 boolean result = FALSE;
852 if (st != NULL)
854 if (isLanguage (Lang_vala))
856 /* All can be a contextual statment as properties can be of any type */
857 result = TRUE;
859 else
861 switch (st->declaration)
863 case DECL_CLASS:
864 case DECL_ENUM:
865 case DECL_INTERFACE:
866 case DECL_NAMESPACE:
867 case DECL_STRUCT:
868 case DECL_UNION:
870 result = TRUE;
871 break;
874 default:
876 result = FALSE;
877 break;
882 return result;
885 static boolean isMember (const statementInfo *const st)
887 boolean result;
888 if (isType (st->context, TOKEN_NAME))
889 result = TRUE;
890 else
891 result = isContextualStatement (st->parent);
892 return result;
895 static void initMemberInfo (statementInfo *const st)
897 accessType accessDefault = ACCESS_UNDEFINED;
899 if (st->parent != NULL) switch (st->parent->declaration)
901 case DECL_ENUM:
902 case DECL_NAMESPACE:
904 accessDefault = ACCESS_UNDEFINED;
905 break;
907 case DECL_CLASS:
909 if (isLanguage (Lang_java))
910 accessDefault = ACCESS_DEFAULT;
911 else
912 accessDefault = ACCESS_PRIVATE;
913 break;
915 case DECL_INTERFACE:
916 case DECL_STRUCT:
917 case DECL_UNION:
919 accessDefault = ACCESS_PUBLIC;
920 break;
922 default:
923 break;
925 st->member.accessDefault = accessDefault;
926 st->member.access = accessDefault;
929 static void reinitStatement (statementInfo *const st, const boolean partial)
931 unsigned int i;
933 if (! partial)
935 st->scope = SCOPE_GLOBAL;
936 if (isContextualStatement (st->parent))
937 st->declaration = DECL_BASE;
938 else
939 st->declaration = DECL_NONE;
941 st->gotParenName = FALSE;
942 st->implementation = IMP_DEFAULT;
943 st->gotArgs = FALSE;
944 st->gotName = FALSE;
945 st->haveQualifyingName = FALSE;
946 st->argEndPosition = 0;
948 st->tokenIndex = 0;
949 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
951 initToken (st->token [i]);
954 initToken (st->context);
955 initToken (st->blockName);
956 vStringClear (st->parentClasses);
958 /* Init member info. */
959 if (! partial)
960 st->member.access = st->member.accessDefault;
962 /* Init first token */
963 if (!partial)
964 initToken(st->firstToken);
967 static void reinitStatementWithToken (statementInfo *const st,
968 tokenInfo *token, const boolean partial)
970 tokenInfo *const save = newToken ();
971 /* given token can be part of reinit statementInfo */
972 copyToken (save, token);
973 reinitStatement (st, partial);
974 token = activeToken (st);
975 copyToken (token, save);
976 deleteToken (save);
977 ++st->tokenIndex; /* this is quite save becouse current tokenIndex = 0 */
980 static void initStatement (statementInfo *const st, statementInfo *const parent)
982 st->parent = parent;
983 initMemberInfo (st);
984 reinitStatement (st, FALSE);
985 if (parent)
987 const tokenInfo *const src = activeToken (parent);
988 tokenInfo *const dst = activeToken (st);
989 copyToken (dst, src);
990 st->tokenIndex++;
995 * Tag generation functions
997 static cKind cTagKind (const tagType type)
999 cKind result = CK_UNDEFINED;
1000 switch (type)
1002 case TAG_CLASS: result = CK_CLASS; break;
1003 case TAG_ENUM: result = CK_ENUMERATION; break;
1004 case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
1005 case TAG_FUNCTION: result = CK_FUNCTION; break;
1006 case TAG_MEMBER: result = CK_MEMBER; break;
1007 case TAG_NAMESPACE: result = CK_NAMESPACE; break;
1008 case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
1009 case TAG_STRUCT: result = CK_STRUCT; break;
1010 case TAG_TYPEDEF: result = CK_TYPEDEF; break;
1011 case TAG_UNION: result = CK_UNION; break;
1012 case TAG_VARIABLE: result = CK_VARIABLE; break;
1013 case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
1015 default: Assert ("Bad C tag type" == NULL); break;
1017 return result;
1020 static csharpKind csharpTagKind (const tagType type)
1022 csharpKind result = CSK_UNDEFINED;
1023 switch (type)
1025 case TAG_CLASS: result = CSK_CLASS; break;
1026 case TAG_ENUM: result = CSK_ENUMERATION; break;
1027 case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
1028 case TAG_EVENT: result = CSK_EVENT; break;
1029 case TAG_FIELD: result = CSK_FIELD ; break;
1030 case TAG_INTERFACE: result = CSK_INTERFACE; break;
1031 case TAG_LOCAL: result = CSK_LOCAL; break;
1032 case TAG_METHOD: result = CSK_METHOD; break;
1033 case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
1034 case TAG_PROPERTY: result = CSK_PROPERTY; break;
1035 case TAG_STRUCT: result = CSK_STRUCT; break;
1036 case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
1038 default: Assert ("Bad C# tag type" == NULL); break;
1040 return result;
1043 static dKind dTagKind (const tagType type)
1045 dKind result = DK_UNDEFINED;
1046 switch (type)
1048 case TAG_CLASS: result = DK_CLASS; break;
1049 case TAG_ENUM: result = DK_ENUMERATION; break;
1050 case TAG_ENUMERATOR: result = DK_ENUMERATOR; break;
1051 case TAG_FUNCTION: result = DK_FUNCTION; break;
1052 case TAG_INTERFACE: result = DK_INTERFACE; break;
1053 case TAG_MEMBER: result = DK_MEMBER; break;
1054 case TAG_NAMESPACE: result = DK_NAMESPACE; break;
1055 case TAG_PROTOTYPE: result = DK_PROTOTYPE; break;
1056 case TAG_STRUCT: result = DK_STRUCT; break;
1057 case TAG_TYPEDEF: result = DK_TYPEDEF; break;
1058 case TAG_UNION: result = DK_UNION; break;
1059 case TAG_VARIABLE: result = DK_VARIABLE; break;
1060 case TAG_EXTERN_VAR: result = DK_EXTERN_VARIABLE; break;
1062 default: Assert ("Bad D tag type" == NULL); break;
1064 return result;
1067 static valaKind valaTagKind (const tagType type)
1069 valaKind result = VK_UNDEFINED;
1070 switch (type)
1072 case TAG_CLASS: result = VK_CLASS; break;
1073 case TAG_ENUM: result = VK_ENUMERATION; break;
1074 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
1075 case TAG_SIGNAL: result = VK_SIGNAL; break;
1076 case TAG_FIELD: result = VK_FIELD ; break;
1077 case TAG_INTERFACE: result = VK_INTERFACE; break;
1078 case TAG_LOCAL: result = VK_LOCAL; break;
1079 case TAG_METHOD: result = VK_METHOD; break;
1080 case TAG_NAMESPACE: result = VK_NAMESPACE; break;
1081 case TAG_PROPERTY: result = VK_PROPERTY; break;
1082 case TAG_STRUCT: result = VK_STRUCT; break;
1084 default: Assert ("Bad Vala tag type" == NULL); break;
1086 return result;
1089 static javaKind javaTagKind (const tagType type)
1091 javaKind result = JK_UNDEFINED;
1092 switch (type)
1094 case TAG_CLASS: result = JK_CLASS; break;
1095 case TAG_FIELD: result = JK_FIELD; break;
1096 case TAG_INTERFACE: result = JK_INTERFACE; break;
1097 case TAG_METHOD: result = JK_METHOD; break;
1098 case TAG_PACKAGE: result = JK_PACKAGE; break;
1100 default: Assert ("Bad Java tag type" == NULL); break;
1102 return result;
1105 static const char *tagName (const tagType type)
1107 const char* result;
1108 if (isLanguage (Lang_java))
1109 result = JavaKinds [javaTagKind (type)].name;
1110 else if (isLanguage (Lang_csharp))
1111 result = CsharpKinds [csharpTagKind (type)].name;
1112 else if (isLanguage (Lang_d))
1113 result = DKinds [dTagKind (type)].name;
1114 else if (isLanguage (Lang_vala))
1115 result = ValaKinds [valaTagKind (type)].name;
1116 else
1117 result = CKinds [cTagKind (type)].name;
1118 return result;
1121 static int tagLetter (const tagType type)
1123 int result;
1124 if (isLanguage (Lang_csharp))
1125 result = CsharpKinds [csharpTagKind (type)].letter;
1126 else if (isLanguage (Lang_d))
1127 result = DKinds [dTagKind (type)].letter;
1128 else if (isLanguage (Lang_java))
1129 result = JavaKinds [javaTagKind (type)].letter;
1130 else if (isLanguage (Lang_vala))
1131 result = ValaKinds [valaTagKind (type)].letter;
1132 else
1133 result = CKinds [cTagKind (type)].letter;
1134 return result;
1138 static boolean includeTag (const tagType type, const boolean isFileScope)
1140 boolean result;
1141 if (isFileScope && ! Option.include.fileScope)
1142 result = FALSE;
1143 else if (isLanguage (Lang_java))
1144 result = JavaKinds [javaTagKind (type)].enabled;
1145 else
1146 result = CKinds [cTagKind (type)].enabled;
1147 return result;
1151 static tagType declToTagType (const declType declaration)
1153 tagType type = TAG_UNDEFINED;
1155 switch (declaration)
1157 case DECL_CLASS: type = TAG_CLASS; break;
1158 case DECL_ENUM: type = TAG_ENUM; break;
1159 case DECL_FUNCTION: type = TAG_FUNCTION; break;
1160 case DECL_FUNCTION_TEMPLATE: type = TAG_FUNCTION; break;
1161 case DECL_INTERFACE:type = TAG_INTERFACE; break;
1162 case DECL_NAMESPACE:type = TAG_NAMESPACE; break;
1163 case DECL_STRUCT: type = TAG_STRUCT; break;
1164 case DECL_UNION: type = TAG_UNION; break;
1166 default: Assert ("Unexpected declaration" == NULL); break;
1168 return type;
1171 static const char* accessField (const statementInfo *const st)
1173 const char* result = NULL;
1175 if ((isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite)) &&
1176 st->scope == SCOPE_FRIEND)
1177 result = "friend";
1178 else if (st->member.access != ACCESS_UNDEFINED)
1179 result = accessString (st->member.access);
1180 return result;
1183 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
1184 const statementInfo *const st, vString *const scope)
1186 /* For selected tag types, append an extension flag designating the
1187 * parent object in which the tag is defined.
1189 switch (type)
1191 default: break;
1193 case TAG_CLASS:
1194 case TAG_ENUM:
1195 case TAG_ENUMERATOR:
1196 case TAG_FIELD:
1197 case TAG_FUNCTION:
1198 case TAG_INTERFACE:
1199 case TAG_MEMBER:
1200 case TAG_METHOD:
1201 case TAG_PROTOTYPE:
1202 case TAG_STRUCT:
1203 case TAG_TYPEDEF:
1204 case TAG_UNION:
1206 if (vStringLength (scope) > 0 &&
1207 (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1209 if (isType (st->context, TOKEN_NAME))
1210 tag->extensionFields.scope [0] = tagName (TAG_CLASS);
1211 else
1212 tag->extensionFields.scope [0] =
1213 tagName (declToTagType (parentDecl (st)));
1214 tag->extensionFields.scope [1] = vStringValue (scope);
1216 if ((type == TAG_CLASS || type == TAG_INTERFACE ||
1217 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
1219 tag->extensionFields.inheritance =
1220 vStringValue (st->parentClasses);
1222 if (st->implementation != IMP_DEFAULT &&
1223 (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
1224 isLanguage (Lang_java) || isLanguage (Lang_d) || isLanguage (Lang_ferite)))
1226 tag->extensionFields.implementation =
1227 implementationString (st->implementation);
1229 if (isMember (st))
1231 tag->extensionFields.access = accessField (st);
1233 if ((TRUE == st->gotArgs) && (TRUE == Option.extensionFields.argList) &&
1234 ((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type)))
1236 tag->extensionFields.arglist = getArglistFromFilePos(
1237 tag->filePosition, tag->name);
1239 break;
1243 if ((TAG_FIELD == tag->type) || (TAG_MEMBER == tag->type) ||
1244 (TAG_EXTERN_VAR == tag->type) || (TAG_TYPEDEF == tag->type) ||
1245 (TAG_VARIABLE == tag->type) || (TAG_METHOD == tag->type) ||
1246 (TAG_PROTOTYPE == tag->type) || (TAG_FUNCTION == tag->type))
1248 if (((TOKEN_NAME == st->firstToken->type) || isDataTypeKeyword(st->firstToken))
1249 && (0 != strcmp(vStringValue(st->firstToken->name), tag->name)))
1251 tag->extensionFields.varType = getVarType(st);
1256 static const char *getVarType (const statementInfo *const st)
1258 static vString *vt = NULL;
1259 unsigned int i;
1261 if (! st->gotArgs)
1262 return vStringValue(st->firstToken->name); /* ignore non-functions */
1264 if (vt == NULL)
1265 vt = vStringNew();
1266 else
1267 vStringClear(vt);
1269 for (i = 0; i < st->tokenIndex; i++)
1271 tokenInfo *t = st->token[i];
1273 switch (t->type)
1275 case TOKEN_NAME: /* user typename */
1276 if (strcmp(vStringValue(t->name), vStringValue(st->firstToken->name)) != 0)
1277 continue;
1278 break;
1279 case TOKEN_KEYWORD:
1280 if (t->keyword != KEYWORD_EXTERN && t->keyword != KEYWORD_STATIC) /* uninteresting keywords */
1281 break;
1282 continue;
1283 case TOKEN_STAR: vStringCatS(vt, " *"); continue;
1284 case TOKEN_ARRAY: vStringCatS(vt, "[]"); continue;
1285 default: continue;
1287 if (vStringLength(vt) > 0)
1288 if (isalpha(vStringValue(vt)[vStringLength(vt) - 1]))
1289 vStringPut(vt, ' ');
1290 vStringCat(vt, t->name);
1292 vStringTerminate(vt);
1293 return vStringValue(vt);
1296 static void addContextSeparator (vString *const scope)
1298 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
1299 vStringCatS (scope, "::");
1300 else if (isLanguage (Lang_java) || isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
1301 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1302 vStringCatS (scope, ".");
1305 static void findScopeHierarchy (vString *const string,
1306 const statementInfo *const st)
1308 const char* const anon = "<anonymous>";
1309 boolean nonAnonPresent = FALSE;
1311 vStringClear (string);
1312 if (isType (st->context, TOKEN_NAME))
1314 vStringCopy (string, st->context->name);
1315 nonAnonPresent = TRUE;
1317 if (st->parent != NULL)
1319 vString *temp = vStringNew ();
1320 const statementInfo *s;
1322 for (s = st->parent ; s != NULL ; s = s->parent)
1324 if (isContextualStatement (s) ||
1325 s->declaration == DECL_NAMESPACE)
1327 vStringCopy (temp, string);
1328 vStringClear (string);
1329 if (isType (s->blockName, TOKEN_NAME))
1331 if (isType (s->context, TOKEN_NAME) &&
1332 vStringLength (s->context->name) > 0)
1334 vStringCat (string, s->context->name);
1335 addContextSeparator (string);
1337 vStringCat (string, s->blockName->name);
1338 nonAnonPresent = TRUE;
1340 else
1341 vStringCopyS (string, anon);
1342 if (vStringLength (temp) > 0)
1343 addContextSeparator (string);
1344 vStringCat (string, temp);
1347 vStringDelete (temp);
1349 if (! nonAnonPresent)
1350 vStringClear (string);
1354 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1355 vString *const scope)
1357 if (Option.include.qualifiedTags &&
1358 scope != NULL && vStringLength (scope) > 0)
1360 vString *const scopedName = vStringNew ();
1362 if (type != TAG_ENUMERATOR)
1363 vStringCopy (scopedName, scope);
1364 else
1366 /* remove last component (i.e. enumeration name) from scope */
1367 const char* const sc = vStringValue (scope);
1368 const char* colon = strrchr (sc, ':');
1369 if (colon != NULL)
1371 while (*colon == ':' && colon > sc)
1372 --colon;
1373 vStringNCopy (scopedName, scope, colon + 1 - sc);
1376 if (vStringLength (scopedName) > 0)
1378 addContextSeparator (scopedName);
1379 vStringCatS (scopedName, e->name);
1380 e->name = vStringValue (scopedName);
1381 makeTagEntry (e);
1383 vStringDelete (scopedName);
1387 static void makeTag (const tokenInfo *const token,
1388 const statementInfo *const st,
1389 boolean isFileScope, const tagType type)
1391 #ifdef DEBUG_C
1392 printToken(token);
1393 fprintf(stderr, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
1394 printStatement(st);
1395 #endif
1396 /* Nothing is really of file scope when it appears in a header file.
1398 isFileScope = (boolean) (isFileScope && ! isHeaderFile ());
1400 if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 /* &&
1401 includeTag (type, isFileScope) */)
1403 vString *scope = vStringNew ();
1404 tagEntryInfo e;
1406 /* take only functions which are introduced by "function ..." */
1407 if (type == TAG_FUNCTION && isLanguage (Lang_ferite) &&
1408 strncmp("function", st->firstToken->name->buffer, 8) != 0)
1410 return;
1413 initTagEntry (&e, vStringValue (token->name));
1415 e.lineNumber = token->lineNumber;
1416 e.filePosition = token->filePosition;
1417 e.isFileScope = isFileScope;
1418 e.kindName = tagName (type);
1419 e.kind = tagLetter (type);
1420 e.type = type;
1422 findScopeHierarchy (scope, st);
1423 addOtherFields (&e, type, st, scope);
1425 #ifdef DEBUG_C
1426 printTagEntry(&e);
1427 #endif
1428 makeTagEntry (&e);
1429 if (NULL != TagEntryFunction)
1430 makeExtraTagEntry (type, &e, scope);
1431 vStringDelete (scope);
1432 if (NULL != e.extensionFields.arglist)
1433 free((char *) e.extensionFields.arglist);
1437 static boolean isValidTypeSpecifier (const declType declaration)
1439 boolean result;
1440 switch (declaration)
1442 case DECL_BASE:
1443 case DECL_CLASS:
1444 case DECL_ENUM:
1445 case DECL_STRUCT:
1446 case DECL_UNION:
1447 result = TRUE;
1448 break;
1450 default:
1451 result = FALSE;
1452 break;
1454 return result;
1457 static void qualifyEnumeratorTag (const statementInfo *const st,
1458 const tokenInfo *const nameToken)
1460 if (isType (nameToken, TOKEN_NAME))
1461 makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
1464 static void qualifyFunctionTag (const statementInfo *const st,
1465 const tokenInfo *const nameToken)
1467 if (isType (nameToken, TOKEN_NAME))
1469 const tagType type = (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1470 ? TAG_METHOD : TAG_FUNCTION;
1471 const boolean isFileScope =
1472 (boolean) (st->member.access == ACCESS_PRIVATE ||
1473 (!isMember (st) && st->scope == SCOPE_STATIC));
1475 makeTag (nameToken, st, isFileScope, type);
1479 static void qualifyFunctionDeclTag (const statementInfo *const st,
1480 const tokenInfo *const nameToken)
1482 if (! isType (nameToken, TOKEN_NAME))
1484 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1485 qualifyFunctionTag (st, nameToken);
1486 else if (st->scope == SCOPE_TYPEDEF)
1487 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1488 else if (isValidTypeSpecifier (st->declaration) &&
1489 ! (isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1490 makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
1493 static void qualifyCompoundTag (const statementInfo *const st,
1494 const tokenInfo *const nameToken)
1496 if (isType (nameToken, TOKEN_NAME))
1498 const tagType type = declToTagType (st->declaration);
1500 if (type != TAG_UNDEFINED)
1501 makeTag (nameToken, st, (boolean) (! isLanguage (Lang_java) &&
1502 ! isLanguage (Lang_csharp) &&
1503 ! isLanguage (Lang_vala)), type);
1507 static void qualifyBlockTag (statementInfo *const st,
1508 const tokenInfo *const nameToken)
1510 switch (st->declaration)
1512 case DECL_CLASS:
1513 case DECL_ENUM:
1514 case DECL_INTERFACE:
1515 case DECL_NAMESPACE:
1516 case DECL_STRUCT:
1517 case DECL_UNION:
1518 qualifyCompoundTag (st, nameToken);
1519 break;
1520 default: break;
1524 static void qualifyVariableTag (const statementInfo *const st,
1525 const tokenInfo *const nameToken)
1527 /* We have to watch that we do not interpret a declaration of the
1528 * form "struct tag;" as a variable definition. In such a case, the
1529 * token preceding the name will be a keyword.
1531 if (! isType (nameToken, TOKEN_NAME))
1533 else if (st->declaration == DECL_IGNORE)
1535 else if (st->scope == SCOPE_TYPEDEF)
1536 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1537 else if (st->declaration == DECL_PACKAGE)
1538 makeTag (nameToken, st, FALSE, TAG_PACKAGE);
1539 else if (st->declaration == DECL_MODULE) /* handle modules in D as namespaces */
1540 makeTag (nameToken, st, FALSE, TAG_NAMESPACE);
1541 else if (isValidTypeSpecifier (st->declaration))
1543 if (isMember (st))
1545 if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1546 makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1547 else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1548 makeTag (nameToken, st, TRUE, TAG_MEMBER);
1550 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1552 else
1554 if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1555 makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
1556 else
1557 makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC), TAG_VARIABLE);
1563 * Parsing functions
1566 static int skipToOneOf (const char *const chars)
1568 int c;
1570 c = cppGetc ();
1571 while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1573 return c;
1576 /* Skip to the next non-white character.
1578 static int skipToNonWhite (void)
1580 int c;
1584 c = cppGetc ();
1586 while (isspace (c));
1588 return c;
1591 /* Skips to the next brace in column 1. This is intended for cases where
1592 * preprocessor constructs result in unbalanced braces.
1594 static void skipToFormattedBraceMatch (void)
1596 int c, next;
1598 c = cppGetc ();
1599 next = cppGetc ();
1600 while (c != EOF && (c != '\n' || next != '}'))
1602 c = next;
1603 next = cppGetc ();
1607 /* Skip to the matching character indicated by the pair string. If skipping
1608 * to a matching brace and any brace is found within a different level of a
1609 * #if conditional statement while brace formatting is in effect, we skip to
1610 * the brace matched by its formatting. It is assumed that we have already
1611 * read the character which starts the group (i.e. the first character of
1612 * "pair").
1614 static void skipToMatch (const char *const pair)
1616 const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
1617 const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
1618 const unsigned int initialLevel = getDirectiveNestLevel ();
1619 const int begin = pair [0], end = pair [1];
1620 const unsigned long inputLineNumber = getInputLineNumber ();
1621 int matchLevel = 1;
1622 int c = '\0';
1623 while (matchLevel > 0 && (c = cppGetc ()) != EOF)
1625 if (c == begin)
1627 ++matchLevel;
1628 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1630 skipToFormattedBraceMatch ();
1631 break;
1634 else if (c == end)
1636 --matchLevel;
1637 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1639 skipToFormattedBraceMatch ();
1640 break;
1644 if (c == EOF)
1646 verbose ("%s: failed to find match for '%c' at line %lu\n",
1647 getInputFileName (), begin, inputLineNumber);
1648 if (braceMatching)
1649 longjmp (Exception, (int) ExceptionBraceFormattingError);
1650 else
1651 longjmp (Exception, (int) ExceptionFormattingError);
1655 static void skipParens (void)
1657 const int c = skipToNonWhite ();
1659 if (c == '(')
1660 skipToMatch ("()");
1661 else
1662 cppUngetc (c);
1665 static void skipBraces (void)
1667 const int c = skipToNonWhite ();
1669 if (c == '{')
1670 skipToMatch ("{}");
1671 else
1672 cppUngetc (c);
1675 static keywordId analyzeKeyword (const char *const name)
1677 const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1678 return id;
1681 static void analyzeIdentifier (tokenInfo *const token)
1683 char *const name = vStringValue (token->name);
1684 const char *replacement = NULL;
1685 boolean parensToo = FALSE;
1687 if (isLanguage (Lang_java) ||
1688 ! isIgnoreToken (name, &parensToo, &replacement))
1690 if (replacement != NULL)
1691 token->keyword = analyzeKeyword (replacement);
1692 else
1693 token->keyword = analyzeKeyword (vStringValue (token->name));
1695 if (token->keyword == KEYWORD_NONE)
1696 token->type = TOKEN_NAME;
1697 else
1698 token->type = TOKEN_KEYWORD;
1700 else
1702 initToken (token);
1703 if (parensToo)
1705 int c = skipToNonWhite ();
1707 if (c == '(')
1708 skipToMatch ("()");
1713 static void readIdentifier (tokenInfo *const token, const int firstChar)
1715 vString *const name = token->name;
1716 int c = firstChar;
1718 initToken (token);
1720 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1721 * the ~ and the class name. */
1722 if (isLanguage (Lang_cpp) && firstChar == '~')
1724 vStringPut (name, c);
1725 c = skipToNonWhite ();
1730 vStringPut (name, c);
1731 c = cppGetc ();
1732 } while (isident (c) || (isLanguage (Lang_vala) && '.' == c));
1733 vStringTerminate (name);
1734 cppUngetc (c); /* unget non-identifier character */
1736 /* Vala supports '?' at end of a type (with or without whitespace before) for nullable types */
1737 if (isLanguage (Lang_vala))
1739 c = skipToNonWhite ();
1740 if ('?' == c)
1741 vStringPut (name, c);
1742 else
1743 cppUngetc (c);
1746 analyzeIdentifier (token);
1749 static void readPackageName (tokenInfo *const token, const int firstChar)
1751 vString *const name = token->name;
1752 int c = firstChar;
1754 initToken (token);
1756 while (isident (c) || c == '.')
1758 vStringPut (name, c);
1759 c = cppGetc ();
1761 vStringTerminate (name);
1762 cppUngetc (c); /* unget non-package character */
1765 static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1767 st->declaration = declaration;
1769 if (declaration == DECL_NAMESPACE && !(isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1771 /* In C++ a namespace is specified one level at a time. */
1772 return;
1774 else
1776 /* In C#, a namespace can also be specified like a Java package name. */
1777 tokenInfo *const token = activeToken (st);
1778 Assert (isType (token, TOKEN_KEYWORD));
1779 readPackageName (token, skipToNonWhite ());
1780 token->type = TOKEN_NAME;
1781 st->gotName = TRUE;
1782 st->haveQualifyingName = TRUE;
1786 static void readPackage (statementInfo *const st)
1788 tokenInfo *const token = activeToken (st);
1789 Assert (isType (token, TOKEN_KEYWORD));
1790 readPackageName (token, skipToNonWhite ());
1791 token->type = TOKEN_NAME;
1792 if (isLanguage (Lang_d))
1793 st->declaration = DECL_MODULE;
1794 else
1795 st->declaration = DECL_PACKAGE;
1796 st->gotName = TRUE;
1797 st->haveQualifyingName = TRUE;
1800 static void processName (statementInfo *const st)
1802 Assert (isType (activeToken (st), TOKEN_NAME));
1803 if (st->gotName && st->declaration == DECL_NONE)
1804 st->declaration = DECL_BASE;
1805 st->gotName = TRUE;
1806 st->haveQualifyingName = TRUE;
1809 static void readOperator (statementInfo *const st)
1811 const char *const acceptable = "+-*/%^&|~!=<>,[]";
1812 const tokenInfo* const prev = prevToken (st,1);
1813 tokenInfo *const token = activeToken (st);
1814 vString *const name = token->name;
1815 int c = skipToNonWhite ();
1817 /* When we arrive here, we have the keyword "operator" in 'name'.
1819 if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1820 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1821 ; /* ignore "operator" keyword if preceded by these keywords */
1822 else if (c == '(')
1824 /* Verify whether this is a valid function call (i.e. "()") operator.
1826 if (cppGetc () == ')')
1828 vStringPut (name, ' '); /* always separate operator from keyword */
1829 c = skipToNonWhite ();
1830 if (c == '(')
1831 vStringCatS (name, "()");
1833 else
1835 skipToMatch ("()");
1836 c = cppGetc ();
1839 else if (isident1 (c))
1841 /* Handle "new" and "delete" operators, and conversion functions
1842 * (per 13.3.1.1.2 [2] of the C++ spec).
1844 boolean whiteSpace = TRUE; /* default causes insertion of space */
1847 if (isspace (c))
1848 whiteSpace = TRUE;
1849 else
1851 if (whiteSpace)
1853 vStringPut (name, ' ');
1854 whiteSpace = FALSE;
1856 vStringPut (name, c);
1858 c = cppGetc ();
1859 } while (! isOneOf (c, "(;") && c != EOF);
1860 vStringTerminate (name);
1862 else if (isOneOf (c, acceptable))
1864 vStringPut (name, ' '); /* always separate operator from keyword */
1867 vStringPut (name, c);
1868 c = cppGetc ();
1869 } while (isOneOf (c, acceptable));
1870 vStringTerminate (name);
1873 cppUngetc (c);
1875 token->type = TOKEN_NAME;
1876 token->keyword = KEYWORD_NONE;
1877 processName (st);
1880 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1882 dest->type = src->type;
1883 dest->keyword = src->keyword;
1884 dest->filePosition = src->filePosition;
1885 dest->lineNumber = src->lineNumber;
1886 vStringCopy (dest->name, src->name);
1889 static void setAccess (statementInfo *const st, const accessType laccess)
1891 if (isMember (st))
1893 if (isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite))
1895 int c = skipToNonWhite ();
1897 if (c == ':')
1898 reinitStatementWithToken (st, prevToken (st, 1), FALSE);
1899 else
1900 cppUngetc (c);
1902 st->member.accessDefault = laccess;
1904 st->member.access = laccess;
1908 static void discardTypeList (tokenInfo *const token)
1910 int c = skipToNonWhite ();
1911 while (isident1 (c))
1913 readIdentifier (token, c);
1914 c = skipToNonWhite ();
1915 if (c == '.' || c == ',')
1916 c = skipToNonWhite ();
1918 cppUngetc (c);
1921 static void addParentClass (statementInfo *const st, tokenInfo *const token)
1923 if (vStringLength (token->name) > 0 &&
1924 vStringLength (st->parentClasses) > 0)
1926 vStringPut (st->parentClasses, ',');
1928 vStringCat (st->parentClasses, token->name);
1931 static void readParents (statementInfo *const st, const int qualifier)
1933 tokenInfo *const token = newToken ();
1934 tokenInfo *const parent = newToken ();
1935 int c;
1939 c = skipToNonWhite ();
1940 if (isident1 (c))
1942 readIdentifier (token, c);
1943 if (isType (token, TOKEN_NAME))
1944 vStringCat (parent->name, token->name);
1945 else
1947 addParentClass (st, parent);
1948 initToken (parent);
1951 else if (c == qualifier)
1952 vStringPut (parent->name, c);
1953 else if (c == '<')
1954 skipToMatch ("<>");
1955 else if (isType (token, TOKEN_NAME))
1957 addParentClass (st, parent);
1958 initToken (parent);
1960 } while (c != '{' && c != EOF);
1961 cppUngetc (c);
1962 deleteToken (parent);
1963 deleteToken (token);
1966 static void processToken (tokenInfo *const token, statementInfo *const st)
1968 switch (token->keyword) /* is it a reserved word? */
1970 default: break;
1972 case KEYWORD_NONE: processName (st); break;
1973 case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
1974 case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
1975 case KEYWORD_CATCH: skipParens (); skipBraces (); break;
1976 case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
1977 case KEYWORD_CLASS: st->declaration = DECL_CLASS; break;
1978 case KEYWORD_CONST: st->declaration = DECL_BASE; break;
1979 case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
1980 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
1981 case KEYWORD_EXTENDS: readParents (st, '.');
1982 setToken (st, TOKEN_NONE); break;
1983 case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
1984 case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
1985 case KEYWORD_IMPLEMENTS:readParents (st, '.');
1986 setToken (st, TOKEN_NONE); break;
1987 case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
1988 case KEYWORD_INT: st->declaration = DECL_BASE; break;
1989 case KEYWORD_BOOLEAN: st->declaration = DECL_BASE; break;
1990 case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
1991 case KEYWORD_SIZE_T: st->declaration = DECL_BASE; break;
1992 case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
1993 case KEYWORD_LONG: st->declaration = DECL_BASE; break;
1994 case KEYWORD_OPERATOR: readOperator (st); break;
1995 case KEYWORD_MODULE: readPackage (st); break;
1996 case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
1997 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
1998 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
1999 case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
2000 case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
2001 case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break;
2002 case KEYWORD_THROWS: discardTypeList (token); break;
2003 case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
2004 case KEYWORD_UNION: st->declaration = DECL_UNION; break;
2005 case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
2006 case KEYWORD_USING: st->declaration = DECL_IGNORE; break;
2007 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
2008 case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
2009 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
2011 case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
2012 case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
2013 case KEYWORD_EVENT:
2015 if (isLanguage (Lang_csharp))
2016 st->declaration = DECL_EVENT;
2017 break;
2019 case KEYWORD_SIGNAL:
2021 if (isLanguage (Lang_vala))
2022 st->declaration = DECL_SIGNAL;
2023 break;
2025 case KEYWORD_EXTERN:
2027 if (! isLanguage (Lang_csharp) || !st->gotName)
2029 /*reinitStatement (st, FALSE);*/
2030 st->scope = SCOPE_EXTERN;
2031 st->declaration = DECL_BASE;
2033 break;
2035 case KEYWORD_STATIC:
2037 if (! isLanguage (Lang_java) && ! isLanguage (Lang_csharp) && ! isLanguage (Lang_vala))
2039 /*reinitStatement (st, FALSE);*/
2040 st->scope = SCOPE_STATIC;
2041 st->declaration = DECL_BASE;
2043 break;
2045 case KEYWORD_IF:
2046 if (isLanguage (Lang_d))
2047 { /* static if (is(typeof(__traits(getMember, a, name)) == function)) */
2048 int c = skipToNonWhite ();
2049 if (c == '(')
2050 skipToMatch ("()");
2052 break;
2057 * Parenthesis handling functions
2060 static void restartStatement (statementInfo *const st)
2062 tokenInfo *const save = newToken ();
2063 tokenInfo *token = activeToken (st);
2065 copyToken (save, token);
2066 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
2067 reinitStatement (st, FALSE);
2068 token = activeToken (st);
2069 copyToken (token, save);
2070 deleteToken (save);
2071 processToken (token, st);
2074 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
2076 * mem-initializer-list:
2077 * mem-initializer, mem-initializer-list
2079 * mem-initializer:
2080 * [::] [nested-name-spec] class-name (...)
2081 * identifier
2083 static void skipMemIntializerList (tokenInfo *const token)
2085 int c;
2089 c = skipToNonWhite ();
2090 while (isident1 (c) || c == ':')
2092 if (c != ':')
2093 readIdentifier (token, c);
2094 c = skipToNonWhite ();
2096 if (c == '<')
2098 skipToMatch ("<>");
2099 c = skipToNonWhite ();
2101 if (c == '(')
2103 skipToMatch ("()");
2104 c = skipToNonWhite ();
2106 } while (c == ',');
2107 cppUngetc (c);
2110 static void skipMacro (statementInfo *const st)
2112 tokenInfo *const prev2 = prevToken (st, 2);
2114 if (isType (prev2, TOKEN_NAME))
2115 retardToken (st);
2116 skipToMatch ("()");
2119 /* Skips over characters following the parameter list. This will be either
2120 * non-ANSI style function declarations or C++ stuff. Our choices:
2122 * C (K&R):
2123 * int func ();
2124 * int func (one, two) int one; float two; {...}
2125 * C (ANSI):
2126 * int func (int one, float two);
2127 * int func (int one, float two) {...}
2128 * C++:
2129 * int foo (...) [const|volatile] [throw (...)];
2130 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2131 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2132 * catch (...) {...}
2134 static boolean skipPostArgumentStuff (statementInfo *const st,
2135 parenInfo *const info)
2137 tokenInfo *const token = activeToken (st);
2138 unsigned int parameters = info->parameterCount;
2139 unsigned int elementCount = 0;
2140 boolean restart = FALSE;
2141 boolean end = FALSE;
2142 int c = skipToNonWhite ();
2146 switch (c)
2148 case ')': break;
2149 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
2150 case '[': skipToMatch ("[]"); break;
2151 case '=': cppUngetc (c); end = TRUE; break;
2152 case '{': cppUngetc (c); end = TRUE; break;
2153 case '}': cppUngetc (c); end = TRUE; break;
2155 case '(':
2157 if (elementCount > 0)
2158 ++elementCount;
2159 skipToMatch ("()");
2160 break;
2163 case ';':
2165 if (parameters == 0 || elementCount < 2)
2167 cppUngetc (c);
2168 end = TRUE;
2170 else if (--parameters == 0)
2171 end = TRUE;
2172 break;
2175 default:
2177 if (isident1 (c))
2179 readIdentifier (token, c);
2180 if (isLanguage(Lang_d))
2182 switch (token->keyword)
2184 /* template constraint */
2185 case KEYWORD_IF:
2186 /* contracts */
2187 case KEYWORD_IN:
2188 case KEYWORD_OUT:
2189 case KEYWORD_BODY:
2190 token->keyword = KEYWORD_CONST;
2191 default:
2192 break;
2195 switch (token->keyword)
2197 case KEYWORD_ATTRIBUTE: skipParens (); break;
2198 case KEYWORD_THROW: skipParens (); break;
2199 case KEYWORD_CONST: break;
2200 case KEYWORD_TRY: break;
2201 case KEYWORD_VOLATILE: break;
2203 case KEYWORD_CATCH: case KEYWORD_CLASS:
2204 case KEYWORD_EXPLICIT: case KEYWORD_EXTERN:
2205 case KEYWORD_FRIEND: case KEYWORD_INLINE:
2206 case KEYWORD_MUTABLE: case KEYWORD_NAMESPACE:
2207 case KEYWORD_NEW: case KEYWORD_OPERATOR:
2208 case KEYWORD_OVERLOAD: case KEYWORD_PRIVATE:
2209 case KEYWORD_PROTECTED: case KEYWORD_PUBLIC:
2210 case KEYWORD_STATIC: case KEYWORD_TEMPLATE:
2211 case KEYWORD_TYPEDEF: case KEYWORD_TYPENAME:
2212 case KEYWORD_USING: case KEYWORD_VIRTUAL:
2213 /* Never allowed within parameter declarations.
2215 restart = TRUE;
2216 end = TRUE;
2217 break;
2219 default:
2220 if (isType (token, TOKEN_NONE))
2222 else if (info->isKnrParamList && info->parameterCount > 0)
2223 ++elementCount;
2224 else
2226 /* If we encounter any other identifier immediately
2227 * following an empty parameter list, this is almost
2228 * certainly one of those Microsoft macro "thingies"
2229 * that the automatic source code generation sticks
2230 * in. Terminate the current statement.
2232 restart = TRUE;
2233 end = TRUE;
2235 break;
2240 if (! end)
2242 c = skipToNonWhite ();
2243 if (c == EOF)
2244 end = TRUE;
2246 } while (! end);
2248 if (restart)
2249 restartStatement (st);
2250 else
2251 setToken (st, TOKEN_NONE);
2252 return (boolean) (c != EOF);
2255 static void skipJavaThrows (statementInfo *const st)
2257 tokenInfo *const token = activeToken (st);
2258 int c = skipToNonWhite ();
2260 if (isident1 (c))
2262 readIdentifier (token, c);
2263 if (token->keyword == KEYWORD_THROWS)
2267 c = skipToNonWhite ();
2268 if (isident1 (c))
2270 readIdentifier (token, c);
2271 c = skipToNonWhite ();
2273 } while (c == '.' || c == ',');
2276 cppUngetc (c);
2277 setToken (st, TOKEN_NONE);
2280 static void skipValaPostParens (statementInfo *const st)
2282 tokenInfo *const token = activeToken (st);
2283 int c = skipToNonWhite ();
2285 while (isident1 (c))
2287 readIdentifier (token, c);
2288 if (token->keyword == KEYWORD_ATTRIBUTE)
2290 /* parse contracts */
2291 skipParens ();
2292 c = skipToNonWhite ();
2294 else if (token->keyword == KEYWORD_THROWS)
2298 c = skipToNonWhite ();
2299 if (isident1 (c))
2301 readIdentifier (token, c);
2302 c = skipToNonWhite ();
2304 } while (c == '.' || c == ',');
2306 else
2307 break;
2309 cppUngetc (c);
2310 setToken (st, TOKEN_NONE);
2313 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2315 const unsigned long inputLineNumber = getInputLineNumber ();
2316 int c = skipToNonWhite ();
2318 cppUngetc (c);
2319 if (isOneOf (c, "{;,="))
2321 else if (isLanguage (Lang_java))
2322 skipJavaThrows (st);
2323 else if (isLanguage (Lang_vala))
2324 skipValaPostParens(st);
2325 else
2327 if (! skipPostArgumentStuff (st, info))
2329 verbose (
2330 "%s: confusing argument declarations beginning at line %lu\n",
2331 getInputFileName (), inputLineNumber);
2332 longjmp (Exception, (int) ExceptionFormattingError);
2337 static int parseParens (statementInfo *const st, parenInfo *const info)
2339 tokenInfo *const token = activeToken (st);
2340 unsigned int identifierCount = 0;
2341 unsigned int depth = 1;
2342 boolean firstChar = TRUE;
2343 int nextChar = '\0';
2345 info->parameterCount = 1;
2348 int c = skipToNonWhite ();
2350 switch (c)
2352 case '&':
2353 case '*':
2355 /* DEBUG_PRINT("parseParens, po++\n"); */
2356 info->isKnrParamList = FALSE;
2357 if (identifierCount == 0)
2358 info->isParamList = FALSE;
2359 initToken (token);
2360 break;
2362 case ':':
2364 info->isKnrParamList = FALSE;
2365 break;
2367 case '.':
2369 info->isNameCandidate = FALSE;
2370 info->isKnrParamList = FALSE;
2371 break;
2373 case ',':
2375 info->isNameCandidate = FALSE;
2376 if (info->isKnrParamList)
2378 ++info->parameterCount;
2379 identifierCount = 0;
2381 break;
2383 case '=':
2385 info->isKnrParamList = FALSE;
2386 info->isNameCandidate = FALSE;
2387 if (firstChar)
2389 info->isParamList = FALSE;
2390 skipMacro (st);
2391 depth = 0;
2393 break;
2395 case '[':
2397 info->isKnrParamList = FALSE;
2398 skipToMatch ("[]");
2399 break;
2401 case '<':
2403 info->isKnrParamList = FALSE;
2404 skipToMatch ("<>");
2405 break;
2407 case ')':
2409 if (firstChar)
2410 info->parameterCount = 0;
2411 --depth;
2412 break;
2414 case '(':
2416 info->isKnrParamList = FALSE;
2417 if (firstChar)
2419 info->isNameCandidate = FALSE;
2420 cppUngetc (c);
2421 skipMacro (st);
2422 depth = 0;
2424 else if (isType (token, TOKEN_PAREN_NAME))
2426 c = skipToNonWhite ();
2427 if (c == '*') /* check for function pointer */
2429 skipToMatch ("()");
2430 c = skipToNonWhite ();
2431 if (c == '(')
2432 skipToMatch ("()");
2434 else
2436 cppUngetc (c);
2437 cppUngetc ('(');
2438 info->nestedArgs = TRUE;
2441 else
2442 ++depth;
2443 break;
2446 default:
2448 if (isident1 (c))
2450 if (++identifierCount > 1)
2451 info->isKnrParamList = FALSE;
2452 readIdentifier (token, c);
2453 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2454 token->type = TOKEN_PAREN_NAME;
2455 else if (isType (token, TOKEN_KEYWORD))
2457 info->isKnrParamList = FALSE;
2458 info->isNameCandidate = FALSE;
2461 else
2463 info->isParamList = FALSE;
2464 info->isKnrParamList = FALSE;
2465 info->isNameCandidate = FALSE;
2466 info->invalidContents = TRUE;
2468 break;
2471 firstChar = FALSE;
2472 } while (! info->nestedArgs && depth > 0 &&
2473 (info->isKnrParamList || info->isNameCandidate));
2475 if (! info->nestedArgs) while (depth > 0)
2477 skipToMatch ("()");
2478 --depth;
2480 if (st->argEndPosition == 0)
2481 st->argEndPosition = mio_tell (File.mio);
2483 if (! info->isNameCandidate)
2484 initToken (token);
2486 return nextChar;
2489 static void initParenInfo (parenInfo *const info)
2491 info->isParamList = TRUE;
2492 info->isKnrParamList = TRUE;
2493 info->isNameCandidate = TRUE;
2494 info->invalidContents = FALSE;
2495 info->nestedArgs = FALSE;
2496 info->parameterCount = 0;
2499 static void analyzeParens (statementInfo *const st)
2501 tokenInfo *const prev = prevToken (st, 1);
2503 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2505 tokenInfo *const token = activeToken (st);
2506 parenInfo info;
2507 int c;
2509 initParenInfo (&info);
2510 parseParens (st, &info);
2512 c = skipToNonWhite ();
2514 cppUngetc (c);
2515 if (info.invalidContents)
2517 reinitStatement (st, FALSE);
2519 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2520 ! st->gotParenName &&
2521 (! info.isParamList || ! st->haveQualifyingName ||
2522 c == '(' ||
2523 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2524 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2526 token->type = TOKEN_NAME;
2527 processName (st);
2528 st->gotParenName = TRUE;
2529 if (isLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME))
2531 st->declaration = DECL_FUNCTION_TEMPLATE;
2532 copyToken (st->blockName, prev);
2535 else if (! st->gotArgs && info.isParamList)
2537 st->gotArgs = TRUE;
2538 setToken (st, TOKEN_ARGS);
2539 advanceToken (st);
2540 analyzePostParens (st, &info);
2542 else
2544 setToken (st, TOKEN_NONE);
2550 * Token parsing functions
2553 static void addContext (statementInfo *const st, const tokenInfo* const token)
2555 if (isType (token, TOKEN_NAME))
2557 if (vStringLength (st->context->name) > 0)
2559 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
2560 vStringCatS (st->context->name, "::");
2561 else if (isLanguage (Lang_java) ||
2562 isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
2563 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
2564 vStringCatS (st->context->name, ".");
2566 vStringCat (st->context->name, token->name);
2567 st->context->type = TOKEN_NAME;
2571 static boolean inheritingDeclaration (declType decl)
2573 return (boolean) (decl == DECL_CLASS ||
2574 decl == DECL_STRUCT ||
2575 decl == DECL_INTERFACE);
2578 static void processColon (statementInfo *const st)
2580 int c = skipToNonWhite ();
2581 const boolean doubleColon = (boolean) (c == ':');
2583 if (doubleColon)
2585 setToken (st, TOKEN_DOUBLE_COLON);
2586 st->haveQualifyingName = FALSE;
2588 else
2590 cppUngetc (c);
2591 if ((((isLanguage (Lang_cpp) &&
2592 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT)) ||
2593 isLanguage (Lang_csharp) || isLanguage (Lang_vala)) &&
2594 inheritingDeclaration (st->declaration)) ||
2595 isLanguage (Lang_d))
2597 readParents (st, ':');
2599 else if (parentDecl (st) == DECL_STRUCT || parentDecl (st) == DECL_CLASS)
2601 c = skipToOneOf (",;");
2602 if (c == ',')
2603 setToken (st, TOKEN_COMMA);
2604 else if (c == ';')
2605 setToken (st, TOKEN_SEMICOLON);
2607 else
2609 const tokenInfo *const prev = prevToken (st, 1);
2610 const tokenInfo *const prev2 = prevToken (st, 2);
2611 if (prev->keyword == KEYWORD_DEFAULT ||
2612 prev2->keyword == KEYWORD_CASE ||
2613 st->parent != NULL)
2615 reinitStatement (st, FALSE);
2621 /* Skips over any initializing value which may follow an '=' character in a
2622 * variable definition.
2624 static int skipInitializer (statementInfo *const st)
2626 boolean done = FALSE;
2627 int c;
2629 while (! done)
2631 c = skipToNonWhite ();
2633 if (c == EOF)
2634 longjmp (Exception, (int) ExceptionFormattingError);
2635 else switch (c)
2637 case ',':
2638 case ';': done = TRUE; break;
2640 case '0':
2641 if (st->implementation == IMP_VIRTUAL)
2642 st->implementation = IMP_PURE_VIRTUAL;
2643 break;
2645 case '[': skipToMatch ("[]"); break;
2646 case '(': skipToMatch ("()"); break;
2647 case '{': skipToMatch ("{}"); break;
2649 case '}':
2650 if (insideEnumBody (st))
2651 done = TRUE;
2652 else if (! isBraceFormat ())
2654 verbose ("%s: unexpected closing brace at line %lu\n",
2655 getInputFileName (), getInputLineNumber ());
2656 longjmp (Exception, (int) ExceptionBraceFormattingError);
2658 break;
2660 default: break;
2663 return c;
2666 static void processInitializer (statementInfo *const st)
2668 const boolean inEnumBody = insideEnumBody (st);
2669 const int c = skipInitializer (st);
2671 if (c == ';')
2672 setToken (st, TOKEN_SEMICOLON);
2673 else if (c == ',')
2674 setToken (st, TOKEN_COMMA);
2675 else if (c == '}' && inEnumBody)
2677 cppUngetc (c);
2678 setToken (st, TOKEN_COMMA);
2680 if (st->scope == SCOPE_EXTERN)
2681 st->scope = SCOPE_GLOBAL;
2684 static void parseIdentifier (statementInfo *const st, const int c)
2686 tokenInfo *const token = activeToken (st);
2688 readIdentifier (token, c);
2689 if (! isType (token, TOKEN_NONE))
2690 processToken (token, st);
2693 static void parseGeneralToken (statementInfo *const st, const int c)
2695 const tokenInfo *const prev = prevToken (st, 1);
2697 if (isident1(c))
2699 parseIdentifier (st, c);
2700 if (isType (st->context, TOKEN_NAME) &&
2701 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2703 initToken (st->context);
2706 else if (isExternCDecl (st, c))
2708 st->declaration = DECL_NOMANGLE;
2709 st->scope = SCOPE_GLOBAL;
2713 /* Reads characters from the pre-processor and assembles tokens, setting
2714 * the current statement state.
2716 static void nextToken (statementInfo *const st)
2718 int c;
2719 tokenInfo *token = activeToken (st);
2722 c = skipToNonWhite();
2723 switch (c)
2725 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2726 case '(': analyzeParens (st); token = activeToken (st); break;
2727 case '*': setToken (st, TOKEN_STAR); break;
2728 case ',': setToken (st, TOKEN_COMMA); break;
2729 case ':': processColon (st); break;
2730 case ';': setToken (st, TOKEN_SEMICOLON); break;
2731 case '<': skipToMatch ("<>"); break;
2732 case '=': processInitializer (st); break;
2733 case '[':
2734 /* Hack for Vala: [..] can be a function attribute.
2735 * Seems not to have bad side effects, but have to test it more. */
2736 if (!isLanguage (Lang_vala))
2737 setToken (st, TOKEN_ARRAY);
2738 skipToMatch ("[]");
2739 break;
2740 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2741 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2742 default: parseGeneralToken (st, c); break;
2744 } while (isType (token, TOKEN_NONE));
2746 /* We want to know about non-keyword variable types */
2747 if (TOKEN_NONE == st->firstToken->type)
2749 if ((TOKEN_NAME == token->type) || isDataTypeKeyword(token))
2750 copyToken(st->firstToken, token);
2755 * Scanning support functions
2757 static unsigned int contextual_fake_count = 0;
2758 static statementInfo *CurrentStatement = NULL;
2760 static statementInfo *newStatement (statementInfo *const parent)
2762 statementInfo *const st = xMalloc (1, statementInfo);
2763 unsigned int i;
2765 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2766 st->token [i] = newToken ();
2768 st->context = newToken ();
2769 st->blockName = newToken ();
2770 st->parentClasses = vStringNew ();
2771 st->firstToken = newToken();
2773 initStatement (st, parent);
2774 CurrentStatement = st;
2776 return st;
2779 static void deleteStatement (void)
2781 statementInfo *const st = CurrentStatement;
2782 statementInfo *const parent = st->parent;
2783 unsigned int i;
2785 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2787 deleteToken(st->token[i]); st->token[i] = NULL;
2789 deleteToken(st->blockName); st->blockName = NULL;
2790 deleteToken(st->context); st->context = NULL;
2791 vStringDelete(st->parentClasses); st->parentClasses = NULL;
2792 deleteToken(st->firstToken);
2793 eFree (st);
2794 CurrentStatement = parent;
2797 static void deleteAllStatements (void)
2799 while (CurrentStatement != NULL)
2800 deleteStatement ();
2803 static boolean isStatementEnd (const statementInfo *const st)
2805 const tokenInfo *const token = activeToken (st);
2806 boolean isEnd;
2808 if (isType (token, TOKEN_SEMICOLON))
2809 isEnd = TRUE;
2810 else if (isType (token, TOKEN_BRACE_CLOSE))
2811 /* Java, D, C#, Vala do not require semicolons to end a block. Neither do
2812 * C++ namespaces. All other blocks require a semicolon to terminate them.
2814 isEnd = (boolean) (isLanguage (Lang_java) || isLanguage (Lang_d) ||
2815 isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
2816 ! isContextualStatement (st));
2817 else
2818 isEnd = FALSE;
2820 return isEnd;
2823 static void checkStatementEnd (statementInfo *const st)
2825 const tokenInfo *const token = activeToken (st);
2826 boolean comma = isType (token, TOKEN_COMMA);
2828 if (comma || isStatementEnd (st))
2830 reinitStatementWithToken (st, activeToken (st), comma);
2832 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2833 cppEndStatement ();
2835 else
2837 cppBeginStatement ();
2838 advanceToken (st);
2842 static void nest (statementInfo *const st, const unsigned int nestLevel)
2844 switch (st->declaration)
2846 case DECL_CLASS:
2847 case DECL_ENUM:
2848 case DECL_INTERFACE:
2849 case DECL_NAMESPACE:
2850 case DECL_NOMANGLE:
2851 case DECL_STRUCT:
2852 case DECL_UNION:
2853 createTags (nestLevel, st);
2854 break;
2855 default:
2856 skipToMatch ("{}");
2857 break;
2859 advanceToken (st);
2860 setToken (st, TOKEN_BRACE_CLOSE);
2863 static void tagCheck (statementInfo *const st)
2865 const tokenInfo *const token = activeToken (st);
2866 const tokenInfo *const prev = prevToken (st, 1);
2867 const tokenInfo *const prev2 = prevToken (st, 2);
2869 switch (token->type)
2871 case TOKEN_NAME:
2873 if (insideEnumBody (st))
2874 qualifyEnumeratorTag (st, token);
2875 break;
2877 #if 0
2878 case TOKEN_PACKAGE:
2880 if (st->haveQualifyingName)
2881 makeTag (token, st, FALSE, TAG_PACKAGE);
2882 break;
2884 #endif
2885 case TOKEN_BRACE_OPEN:
2887 if (isType (prev, TOKEN_ARGS))
2889 if (st->declaration == DECL_FUNCTION_TEMPLATE)
2890 qualifyFunctionTag (st, st->blockName);
2891 else if (st->haveQualifyingName)
2893 if (isType (prev2, TOKEN_NAME))
2894 copyToken (st->blockName, prev2);
2895 /* D structure templates */
2896 if (isLanguage (Lang_d) &&
2897 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT ||
2898 st->declaration == DECL_INTERFACE || st->declaration == DECL_NAMESPACE))
2899 qualifyBlockTag (st, prev2);
2900 else
2902 st->declaration = DECL_FUNCTION;
2903 qualifyFunctionTag (st, prev2);
2907 else if (isContextualStatement (st))
2909 tokenInfo *name_token = (tokenInfo *)prev;
2910 boolean free_name_token = FALSE;
2912 if (isType (name_token, TOKEN_NAME))
2914 if (!isLanguage (Lang_vala))
2915 copyToken (st->blockName, name_token);
2916 else
2918 switch (st->declaration)
2920 case DECL_CLASS:
2921 case DECL_ENUM:
2922 case DECL_INTERFACE:
2923 case DECL_NAMESPACE:
2924 case DECL_STRUCT:
2925 copyToken (st->blockName, name_token);
2926 break;
2928 /* anything else can be a property */
2929 default:
2930 /* makeTag (prev, st, FALSE, TAG_PROPERTY); */
2931 /* FIXME: temporary hack to get properties shown */
2932 makeTag (prev, st, FALSE, TAG_FIELD);
2933 break;
2937 else if (isLanguage (Lang_csharp))
2938 makeTag (prev, st, FALSE, TAG_PROPERTY);
2939 else
2941 tokenInfo *contextual_token = (tokenInfo *)prev;
2942 if(isContextualKeyword (contextual_token))
2944 char buffer[64];
2946 name_token = newToken ();
2947 free_name_token = TRUE;
2948 copyToken (name_token, contextual_token);
2950 sprintf(buffer, "anon_%s_%d", name_token->name->buffer, contextual_fake_count++);
2951 vStringClear(name_token->name);
2952 vStringCatS(name_token->name, buffer);
2954 name_token->type = TOKEN_NAME;
2955 name_token->keyword = KEYWORD_NONE;
2957 advanceToken (st);
2958 contextual_token = activeToken (st);
2959 copyToken (contextual_token, token);
2960 copyToken ((tokenInfo *const)token, name_token);
2961 copyToken (st->blockName, name_token);
2962 copyToken (st->firstToken, name_token);
2965 qualifyBlockTag (st, name_token);
2966 if (free_name_token)
2967 deleteToken (name_token);
2969 break;
2971 case TOKEN_ARRAY:
2972 case TOKEN_SEMICOLON:
2973 case TOKEN_COMMA:
2975 if (insideEnumBody (st))
2977 else if (isType (prev, TOKEN_NAME))
2979 if (isContextualKeyword (prev2))
2980 makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
2981 else
2982 qualifyVariableTag (st, prev);
2984 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
2986 qualifyFunctionDeclTag (st, prev2);
2988 break;
2990 default:
2991 break;
2995 /* Parses the current file and decides whether to write out and tags that
2996 * are discovered.
2998 static void createTags (const unsigned int nestLevel,
2999 statementInfo *const parent)
3001 statementInfo *const st = newStatement (parent);
3003 DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
3004 while (TRUE)
3006 tokenInfo *token;
3008 nextToken (st);
3010 token = activeToken (st);
3012 if (isType (token, TOKEN_BRACE_CLOSE))
3014 if (nestLevel > 0)
3015 break;
3016 else
3018 verbose ("%s: unexpected closing brace at line %lu\n",
3019 getInputFileName (), getInputLineNumber ());
3020 longjmp (Exception, (int) ExceptionBraceFormattingError);
3023 else if (isType (token, TOKEN_DOUBLE_COLON))
3025 addContext (st, prevToken (st, 1));
3026 advanceToken (st);
3028 else
3030 tagCheck (st);/* this can add new token */
3031 if (isType (activeToken (st), TOKEN_BRACE_OPEN))
3032 nest (st, nestLevel + 1);
3033 checkStatementEnd (st);
3036 deleteStatement ();
3037 DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
3040 static boolean findCTags (const unsigned int passCount)
3042 exception_t exception;
3043 boolean retry;
3045 contextual_fake_count = 0;
3047 Assert (passCount < 3);
3048 cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
3050 exception = (exception_t) setjmp (Exception);
3051 retry = FALSE;
3053 if (exception == ExceptionNone)
3055 createTags (0, NULL);
3057 else
3059 deleteAllStatements ();
3060 if (exception == ExceptionBraceFormattingError && passCount == 1)
3062 retry = TRUE;
3063 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3064 getInputFileName ());
3067 cppTerminate ();
3068 return retry;
3071 static void buildKeywordHash (const langType language, unsigned int idx)
3073 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
3074 size_t i;
3075 for (i = 0 ; i < count ; ++i)
3077 const keywordDesc* const p = &KeywordTable [i];
3078 if (p->isValid [idx])
3079 addKeyword (p->name, language, (int) p->id);
3083 static void initializeCParser (const langType language)
3085 Lang_c = language;
3086 buildKeywordHash (language, 0);
3089 static void initializeCppParser (const langType language)
3091 Lang_cpp = language;
3092 buildKeywordHash (language, 1);
3095 static void initializeJavaParser (const langType language)
3097 Lang_java = language;
3098 buildKeywordHash (language, 3);
3101 static void initializeDParser (const langType language)
3103 Lang_d = language;
3104 buildKeywordHash (language, 6);
3107 static void initializeGLSLParser (const langType language)
3109 Lang_glsl = language;
3110 buildKeywordHash (language, 0); /* C keywords */
3113 static void initializeFeriteParser (const langType language)
3115 Lang_ferite = language;
3116 buildKeywordHash (language, 1); /* C++ keywords */
3119 static void initializeCsharpParser (const langType language)
3121 Lang_csharp = language;
3122 buildKeywordHash (language, 2);
3125 static void initializeValaParser (const langType language)
3127 Lang_vala = language;
3128 buildKeywordHash (language, 5);
3131 extern parserDefinition* CParser (void)
3133 static const char *const extensions [] = { "c", "pc", "sc", NULL };
3134 parserDefinition* def = parserNew ("C");
3135 def->kinds = CKinds;
3136 def->kindCount = KIND_COUNT (CKinds);
3137 def->extensions = extensions;
3138 def->parser2 = findCTags;
3139 def->initialize = initializeCParser;
3140 return def;
3143 extern parserDefinition* CppParser (void)
3145 static const char *const extensions [] = {
3146 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3147 "i",
3148 #ifndef CASE_INSENSITIVE_FILENAMES
3149 "C", "H",
3150 #endif
3151 NULL
3153 parserDefinition* def = parserNew ("C++");
3154 def->kinds = CKinds;
3155 def->kindCount = KIND_COUNT (CKinds);
3156 def->extensions = extensions;
3157 def->parser2 = findCTags;
3158 def->initialize = initializeCppParser;
3159 return def;
3162 extern parserDefinition* JavaParser (void)
3164 static const char *const extensions [] = { "java", NULL };
3165 parserDefinition* def = parserNew ("Java");
3166 def->kinds = JavaKinds;
3167 def->kindCount = KIND_COUNT (JavaKinds);
3168 def->extensions = extensions;
3169 def->parser2 = findCTags;
3170 def->initialize = initializeJavaParser;
3171 return def;
3174 extern parserDefinition* DParser (void)
3176 static const char *const extensions [] = { "d", "di", NULL };
3177 parserDefinition* def = parserNew ("D");
3178 def->kinds = DKinds;
3179 def->kindCount = KIND_COUNT (DKinds);
3180 def->extensions = extensions;
3181 def->parser2 = findCTags;
3182 def->initialize = initializeDParser;
3183 return def;
3186 extern parserDefinition* GLSLParser (void)
3188 static const char *const extensions [] = { "glsl", "frag", "vert", NULL };
3189 parserDefinition* def = parserNew ("GLSL");
3190 def->kinds = CKinds;
3191 def->kindCount = KIND_COUNT (CKinds);
3192 def->extensions = extensions;
3193 def->parser2 = findCTags;
3194 def->initialize = initializeGLSLParser;
3195 return def;
3198 extern parserDefinition* FeriteParser (void)
3200 static const char *const extensions [] = { "fe", NULL };
3201 parserDefinition* def = parserNew ("Ferite");
3202 def->kinds = CKinds;
3203 def->kindCount = KIND_COUNT (CKinds);
3204 def->extensions = extensions;
3205 def->parser2 = findCTags;
3206 def->initialize = initializeFeriteParser;
3207 return def;
3210 extern parserDefinition* CsharpParser (void)
3212 static const char *const extensions [] = { "cs", NULL };
3213 parserDefinition* def = parserNew ("C#");
3214 def->kinds = CsharpKinds;
3215 def->kindCount = KIND_COUNT (CsharpKinds);
3216 def->extensions = extensions;
3217 def->parser2 = findCTags;
3218 def->initialize = initializeCsharpParser;
3219 return def;
3222 extern parserDefinition* ValaParser (void)
3224 static const char *const extensions [] = { "vala", NULL };
3225 parserDefinition* def = parserNew ("Vala");
3226 def->kinds = ValaKinds;
3227 def->kindCount = KIND_COUNT (ValaKinds);
3228 def->extensions = extensions;
3229 def->parser2 = findCTags;
3230 def->initialize = initializeValaParser;
3231 return def;
3233 /* vi:set tabstop=8 shiftwidth=4: */