Update of Italian translation
[geany-mirror.git] / tagmanager / ctags / c.c
blobf1fca89ed65aacb0d3822392e321f004240aa063
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 /* Note: some keyword aliases are added in initializeDParser, initializeValaParser */
387 static const keywordDesc KeywordTable [] = {
388 /* C++ */
389 /* ANSI C | C# Java */
390 /* | | | | Vera */
391 /* | | | | | Vala */
392 /* | | | | | | D */
393 /* keyword keyword ID | | | | | | | */
394 { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0, 0, 1 } },
395 { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0, 1, 1 } },
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 { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1, 1, 1 } },
419 { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1, 0, 0 } },
420 { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0, 0, 1 } },
421 { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1, 0, 0 } },
422 { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1, 1, 0 } },
423 { "extern", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
424 { "final", KEYWORD_FINAL, { 0, 1, 0, 1, 0, 0, 1 } },
425 { "finally", KEYWORD_FINALLY, { 0, 0, 0, 0, 0, 1, 1 } },
426 { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0, 1, 1 } },
427 { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0, 1, 1 } },
428 { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0, 0, 0 } },
429 { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1, 0, 1 } },
430 { "get", KEYWORD_GET, { 0, 0, 0, 0, 0, 1, 0 } },
431 { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0, 1, 1 } },
432 { "if", KEYWORD_IF, { 1, 1, 1, 1, 0, 1, 1 } },
433 { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0, 0, 0 } },
434 { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0, 0, 1 } },
435 { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0, 1, 0 } },
436 { "in", KEYWORD_IN, { 0, 0, 0, 0, 0, 0, 1 } },
437 { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1, 0, 0 } },
438 { "inout", KEYWORD_CONST, { 0, 0, 0, 0, 0, 0, 1 } }, /* treat like const */
439 { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1, 0, 0 } },
440 { "int", KEYWORD_INT, { 1, 1, 1, 1, 0, 1, 1 } },
441 { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1, 0, 0 } },
442 { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1, 1, 1 } },
443 { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0, 0, 0 } },
444 { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1, 0, 0 } },
445 { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0, 1, 1 } },
446 { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
447 { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
448 { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
449 { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
450 { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0, 0, 0 } },
451 { "module", KEYWORD_MODULE, { 0, 0, 0, 0, 0, 0, 1 } },
452 { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0, 1, 0 } },
453 { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0, 0, 0 } },
454 { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0, 1, 1 } },
455 { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1, 0, 0 } },
456 { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0, 0, 0 } },
457 { "out", KEYWORD_OUT, { 0, 0, 0, 0, 0, 1, 1 } },
458 { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1, 0, 0 } },
459 { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0, 0, 0 } },
460 { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0, 1, 1 } },
461 { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0, 0, 1 } },
462 { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1, 0, 0 } },
463 { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1, 0, 0 } },
464 { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0, 1, 1 } },
465 { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1, 0, 0 } },
466 { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1, 1, 1 } },
467 { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1, 1, 1 } },
468 { "ref", KEYWORD_REF, { 0, 0, 0, 0, 0, 1, 1 } },
469 { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0, 0, 0 } },
470 { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0, 1, 1 } },
471 { "set", KEYWORD_SET, { 0, 0, 0, 0, 0, 1, 0 } },
472 { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1, 0, 0 } },
473 { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0, 1, 1 } },
474 { "signal", KEYWORD_SIGNAL, { 0, 0, 0, 0, 0, 1, 0 } },
475 { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0, 0, 0 } },
476 { "size_t", KEYWORD_SIZE_T, { 1, 1, 0, 0, 0, 1, 1 } },
477 { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
478 { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1, 1, 1 } },
479 { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1, 1, 0 } },
480 { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0, 1, 1 } },
481 { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0, 1, 1 } },
482 { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0, 0, 1 } },
483 { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1, 0, 0 } },
484 { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0, 0, 0 } },
485 { "template", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
486 { "this", KEYWORD_THIS, { 0, 0, 1, 1, 0, 1, 0 } }, /* 0 to allow D ctor tags */
487 { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0, 1, 1 } },
488 { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0, 1, 0 } },
489 { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
490 { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1, 0, 0 } },
491 { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0, 0, 0 } },
492 { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0, 1, 1 } },
493 { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1, 0, 1 } },
494 { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0, 0, 0 } },
495 { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0, 1, 1 } },
496 { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0, 1, 1 } },
497 { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0, 0, 1 } },
498 { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0, 0, 1 } },
499 { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0, 1, 1 } },
500 { "using", KEYWORD_USING, { 0, 1, 1, 0, 0, 1, 0 } },
501 { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1, 1, 0 } },
502 { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1, 1, 1 } },
503 { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0, 0, 1 } },
504 { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0, 0, 1 } },
505 { "weak", KEYWORD_WEAK, { 0, 0, 0, 0, 0, 1, 0 } },
506 { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0, 1, 1 } }
511 * FUNCTION PROTOTYPES
513 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
514 static void copyToken (tokenInfo *const dest, const tokenInfo *const src);
515 static const char *getVarType (const statementInfo *const st);
518 * FUNCTION DEFINITIONS
521 /* Debugging functions added by Biswa */
522 #if defined(DEBUG_C) && DEBUG_C
523 static char *tokenTypeName[] = {
524 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
525 "package", "paren-name", "';'", "spec", "*", "[]", "count"
528 static char *tagScopeNames[] = {
529 "global", "static", "extern", "friend", "typedef", "count"};
531 static char *declTypeNames[] = {
532 "none", "base", "class", "enum", "function", "ignore", "interface",
533 "namespace", "nomangle", "package", "struct", "union", "count"};
535 static char *impTypeNames[] = {
536 "default", "abstract", "virtual", "pure-virtual", "count"};
538 void printToken(const tokenInfo *const token)
540 fprintf(stderr, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName[token->type],
541 token->keyword, vStringValue(token->name));
544 void printTagEntry(const tagEntryInfo *tag)
546 fprintf(stderr, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag->name,
547 tag->kindName, tag->extensionFields.implementation, tag->extensionFields.scope[1],
548 tag->extensionFields.varType);
551 void printStatement(const statementInfo *const statement)
553 int i;
554 statementInfo *st = (statementInfo *) statement;
555 while (NULL != st)
557 fprintf(stderr, "Statement Info:\n------------------------\n");
558 fprintf(stderr, "scope: %s, decl: %s, impl: %s\n", tagScopeNames[st->scope],
559 declTypeNames[st->declaration], impTypeNames[st->implementation]);
560 for (i=0; i < NumTokens; ++i)
562 fprintf(stderr, "Token %d %s: ", i, (i == st->tokenIndex)?"(current)":"");
563 printToken(st->token[i]);
565 fprintf(stderr, "Context: ");
566 printToken(st->context);
567 fprintf(stderr, "Block: ");
568 printToken(st->blockName);
569 fprintf(stderr, "Parent classes: %s\n", vStringValue(st->parentClasses));
570 fprintf(stderr, "First token: ");
571 printToken(st->firstToken);
572 if (NULL != st->parent)
573 fprintf(stderr, "Printing Parent:\n");
574 st = st->parent;
576 fprintf(stderr, "-----------------------------------------------\n");
578 #endif
580 extern boolean includingDefineTags (void)
582 if (isLanguage(Lang_c) ||
583 isLanguage(Lang_cpp) ||
584 isLanguage(Lang_csharp) ||
585 isLanguage(Lang_ferite) ||
586 isLanguage(Lang_glsl) ||
587 isLanguage(Lang_vala))
588 return CKinds [CK_DEFINE].enabled;
590 return FALSE;
594 * Token management
597 static void initToken (tokenInfo* const token)
599 token->type = TOKEN_NONE;
600 token->keyword = KEYWORD_NONE;
601 token->lineNumber = getSourceLineNumber();
602 token->filePosition = getInputFilePosition();
603 vStringClear(token->name);
606 static void advanceToken (statementInfo* const st)
608 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
609 st->tokenIndex = 0;
610 else
611 ++st->tokenIndex;
612 initToken(st->token[st->tokenIndex]);
615 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
617 unsigned int tokenIndex;
618 unsigned int num = (unsigned int) NumTokens;
619 Assert(n < num);
620 tokenIndex = (st->tokenIndex + num - n) % num;
622 return st->token[tokenIndex];
625 static void setToken (statementInfo *const st, const tokenType type)
627 tokenInfo *token;
628 token = activeToken (st);
629 initToken(token);
630 token->type = type;
633 static void retardToken (statementInfo *const st)
635 if (st->tokenIndex == 0)
636 st->tokenIndex = (unsigned int) NumTokens - 1;
637 else
638 --st->tokenIndex;
639 setToken(st, TOKEN_NONE);
642 static tokenInfo *newToken (void)
644 tokenInfo *const token = xMalloc (1, tokenInfo);
645 token->name = vStringNew();
646 initToken(token);
647 return token;
650 static void deleteToken (tokenInfo *const token)
652 if (token != NULL)
654 vStringDelete(token->name);
655 eFree(token);
659 static const char *accessString (const accessType laccess)
661 static const char *const names [] = {
662 "?", "private", "protected", "public", "default"
664 Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
665 Assert ((int) laccess < ACCESS_COUNT);
666 return names[(int) laccess];
669 static const char *implementationString (const impType imp)
671 static const char *const names [] = {
672 "?", "abstract", "virtual", "pure virtual"
674 Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
675 Assert ((int) imp < IMP_COUNT);
676 return names [(int) imp];
680 * Debugging functions
683 #ifdef TM_DEBUG
685 #define boolString(c) ((c) ? "TRUE" : "FALSE")
687 static const char *tokenString (const tokenType type)
689 static const char *const names [] = {
690 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
691 "package", "paren-name", "semicolon", "specifier", "*", "[]"
693 Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
694 Assert ((int) type < TOKEN_COUNT);
695 return names[(int) type];
698 static const char *scopeString (const tagScope scope)
700 static const char *const names [] = {
701 "global", "static", "extern", "friend", "typedef"
703 Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
704 Assert ((int) scope < SCOPE_COUNT);
705 return names[(int) scope];
708 static const char *declString (const declType declaration)
710 static const char *const names [] = {
711 "?", "base", "class", "enum", "event", "signal", "function",
712 "function template", "ignore", "interface", "module", "namespace",
713 "no mangle", "package", "struct", "union",
715 Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
716 Assert ((int) declaration < DECL_COUNT);
717 return names[(int) declaration];
720 static const char *keywordString (const keywordId keyword)
722 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
723 const char *name = "none";
724 size_t i;
725 for (i = 0 ; i < count ; ++i)
727 const keywordDesc *p = &KeywordTable[i];
729 if (p->id == keyword)
731 name = p->name;
732 break;
735 return name;
738 static void UNUSED pt (tokenInfo *const token)
740 if (isType (token, TOKEN_NAME))
741 printf("type: %-12s: %-13s line: %lu\n",
742 tokenString (token->type), vStringValue (token->name),
743 token->lineNumber);
744 else if (isType (token, TOKEN_KEYWORD))
745 printf("type: %-12s: %-13s line: %lu\n",
746 tokenString (token->type), keywordString (token->keyword),
747 token->lineNumber);
748 else
749 printf("type: %-12s line: %lu\n",
750 tokenString (token->type), token->lineNumber);
753 static void UNUSED ps (statementInfo *const st)
755 unsigned int i;
756 printf("scope: %s decl: %s gotName: %s gotParenName: %s\n",
757 scopeString (st->scope), declString (st->declaration),
758 boolString (st->gotName), boolString (st->gotParenName));
759 printf("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
760 printf("access: %s default: %s\n", accessString (st->member.access),
761 accessString (st->member.accessDefault));
762 printf("token : ");
763 pt(activeToken (st));
764 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
766 printf("prev %u : ", i);
767 pt(prevToken (st, i));
769 printf("context: ");
770 pt(st->context);
773 #endif
776 * Statement management
779 static boolean isDataTypeKeyword (const tokenInfo *const token)
781 switch (token->keyword)
783 case KEYWORD_BOOLEAN:
784 case KEYWORD_BYTE:
785 case KEYWORD_CHAR:
786 case KEYWORD_DOUBLE:
787 case KEYWORD_FLOAT:
788 case KEYWORD_INT:
789 case KEYWORD_LONG:
790 case KEYWORD_SHORT:
791 case KEYWORD_VOID:
792 case KEYWORD_WCHAR_T:
793 case KEYWORD_SIZE_T:
794 return TRUE;
795 default:
796 return FALSE;
800 #if 0
801 static boolean isVariableKeyword (const tokenInfo *const token)
803 switch (token->keyword)
805 case KEYWORD_CONST:
806 case KEYWORD_EXTERN:
807 case KEYWORD_REGISTER:
808 case KEYWORD_STATIC:
809 case KEYWORD_VIRTUAL:
810 case KEYWORD_SIGNED:
811 case KEYWORD_UNSIGNED:
812 return TRUE;
813 default:
814 return FALSE;
817 #endif
819 static boolean isContextualKeyword (const tokenInfo *const token)
821 boolean result;
822 switch (token->keyword)
824 case KEYWORD_CLASS:
825 case KEYWORD_ENUM:
826 case KEYWORD_INTERFACE:
827 case KEYWORD_NAMESPACE:
828 case KEYWORD_STRUCT:
829 case KEYWORD_UNION:
831 result = TRUE;
832 break;
835 default:
837 result = FALSE;
838 break;
841 return result;
844 static boolean isContextualStatement (const statementInfo *const st)
846 boolean result = FALSE;
848 if (st != NULL)
850 if (isLanguage (Lang_vala))
852 /* All can be a contextual statment as properties can be of any type */
853 result = TRUE;
855 else
857 switch (st->declaration)
859 case DECL_CLASS:
860 case DECL_ENUM:
861 case DECL_INTERFACE:
862 case DECL_NAMESPACE:
863 case DECL_STRUCT:
864 case DECL_UNION:
866 result = TRUE;
867 break;
870 default:
872 result = FALSE;
873 break;
878 return result;
881 static boolean isMember (const statementInfo *const st)
883 boolean result;
884 if (isType (st->context, TOKEN_NAME))
885 result = TRUE;
886 else
887 result = isContextualStatement (st->parent);
888 return result;
891 static void initMemberInfo (statementInfo *const st)
893 accessType accessDefault = ACCESS_UNDEFINED;
895 if (st->parent != NULL) switch (st->parent->declaration)
897 case DECL_ENUM:
898 case DECL_NAMESPACE:
900 accessDefault = ACCESS_UNDEFINED;
901 break;
903 case DECL_CLASS:
905 if (isLanguage (Lang_java))
906 accessDefault = ACCESS_DEFAULT;
907 else
908 accessDefault = ACCESS_PRIVATE;
909 break;
911 case DECL_INTERFACE:
912 case DECL_STRUCT:
913 case DECL_UNION:
915 accessDefault = ACCESS_PUBLIC;
916 break;
918 default:
919 break;
921 st->member.accessDefault = accessDefault;
922 st->member.access = accessDefault;
925 static void reinitStatement (statementInfo *const st, const boolean partial)
927 unsigned int i;
929 if (! partial)
931 st->scope = SCOPE_GLOBAL;
932 if (isContextualStatement (st->parent))
933 st->declaration = DECL_BASE;
934 else
935 st->declaration = DECL_NONE;
937 st->gotParenName = FALSE;
938 st->implementation = IMP_DEFAULT;
939 st->gotArgs = FALSE;
940 st->gotName = FALSE;
941 st->haveQualifyingName = FALSE;
942 st->argEndPosition = 0;
944 st->tokenIndex = 0;
945 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
947 initToken (st->token [i]);
950 initToken (st->context);
951 initToken (st->blockName);
952 vStringClear (st->parentClasses);
954 /* Init member info. */
955 if (! partial)
956 st->member.access = st->member.accessDefault;
958 /* Init first token */
959 if (!partial)
960 initToken(st->firstToken);
963 static void reinitStatementWithToken (statementInfo *const st,
964 tokenInfo *token, const boolean partial)
966 tokenInfo *const save = newToken ();
967 /* given token can be part of reinit statementInfo */
968 copyToken (save, token);
969 reinitStatement (st, partial);
970 token = activeToken (st);
971 copyToken (token, save);
972 deleteToken (save);
973 ++st->tokenIndex; /* this is quite save becouse current tokenIndex = 0 */
976 static void initStatement (statementInfo *const st, statementInfo *const parent)
978 st->parent = parent;
979 initMemberInfo (st);
980 reinitStatement (st, FALSE);
981 if (parent)
983 const tokenInfo *const src = activeToken (parent);
984 tokenInfo *const dst = activeToken (st);
985 copyToken (dst, src);
986 st->tokenIndex++;
991 * Tag generation functions
993 static cKind cTagKind (const tagType type)
995 cKind result = CK_UNDEFINED;
996 switch (type)
998 case TAG_CLASS: result = CK_CLASS; break;
999 case TAG_ENUM: result = CK_ENUMERATION; break;
1000 case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
1001 case TAG_FUNCTION: result = CK_FUNCTION; break;
1002 case TAG_MEMBER: result = CK_MEMBER; break;
1003 case TAG_NAMESPACE: result = CK_NAMESPACE; break;
1004 case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
1005 case TAG_STRUCT: result = CK_STRUCT; break;
1006 case TAG_TYPEDEF: result = CK_TYPEDEF; break;
1007 case TAG_UNION: result = CK_UNION; break;
1008 case TAG_VARIABLE: result = CK_VARIABLE; break;
1009 case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
1011 default: Assert ("Bad C tag type" == NULL); break;
1013 return result;
1016 static csharpKind csharpTagKind (const tagType type)
1018 csharpKind result = CSK_UNDEFINED;
1019 switch (type)
1021 case TAG_CLASS: result = CSK_CLASS; break;
1022 case TAG_ENUM: result = CSK_ENUMERATION; break;
1023 case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
1024 case TAG_EVENT: result = CSK_EVENT; break;
1025 case TAG_FIELD: result = CSK_FIELD ; break;
1026 case TAG_INTERFACE: result = CSK_INTERFACE; break;
1027 case TAG_LOCAL: result = CSK_LOCAL; break;
1028 case TAG_METHOD: result = CSK_METHOD; break;
1029 case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
1030 case TAG_PROPERTY: result = CSK_PROPERTY; break;
1031 case TAG_STRUCT: result = CSK_STRUCT; break;
1032 case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
1034 default: Assert ("Bad C# tag type" == NULL); break;
1036 return result;
1039 static dKind dTagKind (const tagType type)
1041 dKind result = DK_UNDEFINED;
1042 switch (type)
1044 case TAG_CLASS: result = DK_CLASS; break;
1045 case TAG_ENUM: result = DK_ENUMERATION; break;
1046 case TAG_ENUMERATOR: result = DK_ENUMERATOR; break;
1047 case TAG_FUNCTION: result = DK_FUNCTION; break;
1048 case TAG_INTERFACE: result = DK_INTERFACE; break;
1049 case TAG_MEMBER: result = DK_MEMBER; break;
1050 case TAG_NAMESPACE: result = DK_NAMESPACE; break;
1051 case TAG_PROTOTYPE: result = DK_PROTOTYPE; break;
1052 case TAG_STRUCT: result = DK_STRUCT; break;
1053 case TAG_TYPEDEF: result = DK_TYPEDEF; break;
1054 case TAG_UNION: result = DK_UNION; break;
1055 case TAG_VARIABLE: result = DK_VARIABLE; break;
1056 case TAG_EXTERN_VAR: result = DK_EXTERN_VARIABLE; break;
1058 default: Assert ("Bad D tag type" == NULL); break;
1060 return result;
1063 static valaKind valaTagKind (const tagType type)
1065 valaKind result = VK_UNDEFINED;
1066 switch (type)
1068 case TAG_CLASS: result = VK_CLASS; break;
1069 case TAG_ENUM: result = VK_ENUMERATION; break;
1070 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
1071 case TAG_SIGNAL: result = VK_SIGNAL; break;
1072 case TAG_FIELD: result = VK_FIELD ; break;
1073 case TAG_INTERFACE: result = VK_INTERFACE; break;
1074 case TAG_LOCAL: result = VK_LOCAL; break;
1075 case TAG_METHOD: result = VK_METHOD; break;
1076 case TAG_NAMESPACE: result = VK_NAMESPACE; break;
1077 case TAG_PROPERTY: result = VK_PROPERTY; break;
1078 case TAG_STRUCT: result = VK_STRUCT; break;
1080 default: Assert ("Bad Vala tag type" == NULL); break;
1082 return result;
1085 static javaKind javaTagKind (const tagType type)
1087 javaKind result = JK_UNDEFINED;
1088 switch (type)
1090 case TAG_CLASS: result = JK_CLASS; break;
1091 case TAG_FIELD: result = JK_FIELD; break;
1092 case TAG_INTERFACE: result = JK_INTERFACE; break;
1093 case TAG_METHOD: result = JK_METHOD; break;
1094 case TAG_PACKAGE: result = JK_PACKAGE; break;
1096 default: Assert ("Bad Java tag type" == NULL); break;
1098 return result;
1101 static const char *tagName (const tagType type)
1103 const char* result;
1104 if (isLanguage (Lang_java))
1105 result = JavaKinds [javaTagKind (type)].name;
1106 else if (isLanguage (Lang_csharp))
1107 result = CsharpKinds [csharpTagKind (type)].name;
1108 else if (isLanguage (Lang_d))
1109 result = DKinds [dTagKind (type)].name;
1110 else if (isLanguage (Lang_vala))
1111 result = ValaKinds [valaTagKind (type)].name;
1112 else
1113 result = CKinds [cTagKind (type)].name;
1114 return result;
1117 static int tagLetter (const tagType type)
1119 int result;
1120 if (isLanguage (Lang_csharp))
1121 result = CsharpKinds [csharpTagKind (type)].letter;
1122 else if (isLanguage (Lang_d))
1123 result = DKinds [dTagKind (type)].letter;
1124 else if (isLanguage (Lang_java))
1125 result = JavaKinds [javaTagKind (type)].letter;
1126 else if (isLanguage (Lang_vala))
1127 result = ValaKinds [valaTagKind (type)].letter;
1128 else
1129 result = CKinds [cTagKind (type)].letter;
1130 return result;
1134 static boolean includeTag (const tagType type, const boolean isFileScope)
1136 boolean result;
1137 if (isFileScope && ! Option.include.fileScope)
1138 result = FALSE;
1139 else if (isLanguage (Lang_java))
1140 result = JavaKinds [javaTagKind (type)].enabled;
1141 else
1142 result = CKinds [cTagKind (type)].enabled;
1143 return result;
1147 static tagType declToTagType (const declType declaration)
1149 tagType type = TAG_UNDEFINED;
1151 switch (declaration)
1153 case DECL_CLASS: type = TAG_CLASS; break;
1154 case DECL_ENUM: type = TAG_ENUM; break;
1155 case DECL_FUNCTION: type = TAG_FUNCTION; break;
1156 case DECL_FUNCTION_TEMPLATE: type = TAG_FUNCTION; break;
1157 case DECL_INTERFACE:type = TAG_INTERFACE; break;
1158 case DECL_NAMESPACE:type = TAG_NAMESPACE; break;
1159 case DECL_STRUCT: type = TAG_STRUCT; break;
1160 case DECL_UNION: type = TAG_UNION; break;
1162 default: Assert ("Unexpected declaration" == NULL); break;
1164 return type;
1167 static const char* accessField (const statementInfo *const st)
1169 const char* result = NULL;
1171 if ((isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite)) &&
1172 st->scope == SCOPE_FRIEND)
1173 result = "friend";
1174 else if (st->member.access != ACCESS_UNDEFINED)
1175 result = accessString (st->member.access);
1176 return result;
1179 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
1180 const statementInfo *const st, vString *const scope)
1182 /* For selected tag types, append an extension flag designating the
1183 * parent object in which the tag is defined.
1185 switch (type)
1187 default: break;
1189 case TAG_NAMESPACE:
1190 /* D nested template block */
1191 if (!isLanguage(Lang_d))
1192 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 if (isLanguage(Lang_d) && pair[0] == '<')
1624 return; /* ignore e.g. Foo!(x < 2) */
1625 while (matchLevel > 0 && (c = cppGetc ()) != EOF)
1627 if (c == begin)
1629 ++matchLevel;
1630 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1632 skipToFormattedBraceMatch ();
1633 break;
1636 else if (c == end)
1638 --matchLevel;
1639 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1641 skipToFormattedBraceMatch ();
1642 break;
1646 if (c == EOF)
1648 verbose ("%s: failed to find match for '%c' at line %lu\n",
1649 getInputFileName (), begin, inputLineNumber);
1650 if (braceMatching)
1651 longjmp (Exception, (int) ExceptionBraceFormattingError);
1652 else
1653 longjmp (Exception, (int) ExceptionFormattingError);
1657 static void skipParens (void)
1659 const int c = skipToNonWhite ();
1661 if (c == '(')
1662 skipToMatch ("()");
1663 else
1664 cppUngetc (c);
1667 static void skipBraces (void)
1669 const int c = skipToNonWhite ();
1671 if (c == '{')
1672 skipToMatch ("{}");
1673 else
1674 cppUngetc (c);
1677 static keywordId analyzeKeyword (const char *const name)
1679 const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1681 /* ignore D @attributes, but show them in function signatures */
1682 if (isLanguage(Lang_d) && id == KEYWORD_NONE && name[0] == '@')
1683 return KEYWORD_CONST;
1684 return id;
1687 static void analyzeIdentifier (tokenInfo *const token)
1689 char *const name = vStringValue (token->name);
1690 const char *replacement = NULL;
1691 boolean parensToo = FALSE;
1693 if (isLanguage (Lang_java) ||
1694 ! isIgnoreToken (name, &parensToo, &replacement))
1696 if (replacement != NULL)
1697 token->keyword = analyzeKeyword (replacement);
1698 else
1699 token->keyword = analyzeKeyword (vStringValue (token->name));
1701 if (token->keyword == KEYWORD_NONE)
1702 token->type = TOKEN_NAME;
1703 else
1704 token->type = TOKEN_KEYWORD;
1706 else
1708 initToken (token);
1709 if (parensToo)
1711 int c = skipToNonWhite ();
1713 if (c == '(')
1714 skipToMatch ("()");
1719 static void readIdentifier (tokenInfo *const token, const int firstChar)
1721 vString *const name = token->name;
1722 int c = firstChar;
1724 initToken (token);
1726 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1727 * the ~ and the class name. */
1728 if (isLanguage (Lang_cpp) && firstChar == '~')
1730 vStringPut (name, c);
1731 c = skipToNonWhite ();
1736 vStringPut (name, c);
1737 c = cppGetc ();
1738 } while (isident (c) || (isLanguage (Lang_vala) && '.' == c));
1739 vStringTerminate (name);
1740 cppUngetc (c); /* unget non-identifier character */
1742 /* Vala supports '?' at end of a type (with or without whitespace before) for nullable types */
1743 if (isLanguage (Lang_vala))
1745 c = skipToNonWhite ();
1746 if ('?' == c)
1747 vStringPut (name, c);
1748 else
1749 cppUngetc (c);
1752 analyzeIdentifier (token);
1755 static void readPackageName (tokenInfo *const token, const int firstChar)
1757 vString *const name = token->name;
1758 int c = firstChar;
1760 initToken (token);
1762 while (isident (c) || c == '.')
1764 vStringPut (name, c);
1765 c = cppGetc ();
1767 vStringTerminate (name);
1768 cppUngetc (c); /* unget non-package character */
1771 static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1773 st->declaration = declaration;
1775 if (declaration == DECL_NAMESPACE && !(isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1777 /* In C++ a namespace is specified one level at a time. */
1778 return;
1780 else
1782 /* In C#, a namespace can also be specified like a Java package name. */
1783 tokenInfo *const token = activeToken (st);
1784 Assert (isType (token, TOKEN_KEYWORD));
1785 readPackageName (token, skipToNonWhite ());
1786 token->type = TOKEN_NAME;
1787 st->gotName = TRUE;
1788 st->haveQualifyingName = TRUE;
1792 static void readPackage (statementInfo *const st)
1794 tokenInfo *const token = activeToken (st);
1795 Assert (isType (token, TOKEN_KEYWORD));
1796 readPackageName (token, skipToNonWhite ());
1797 token->type = TOKEN_NAME;
1798 if (isLanguage (Lang_d))
1799 st->declaration = DECL_MODULE;
1800 else
1801 st->declaration = DECL_PACKAGE;
1802 st->gotName = TRUE;
1803 st->haveQualifyingName = TRUE;
1806 static void processName (statementInfo *const st)
1808 Assert (isType (activeToken (st), TOKEN_NAME));
1809 if (st->gotName && st->declaration == DECL_NONE)
1810 st->declaration = DECL_BASE;
1811 st->gotName = TRUE;
1812 st->haveQualifyingName = TRUE;
1815 static void readOperator (statementInfo *const st)
1817 const char *const acceptable = "+-*/%^&|~!=<>,[]";
1818 const tokenInfo* const prev = prevToken (st,1);
1819 tokenInfo *const token = activeToken (st);
1820 vString *const name = token->name;
1821 int c = skipToNonWhite ();
1823 /* When we arrive here, we have the keyword "operator" in 'name'.
1825 if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1826 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1827 ; /* ignore "operator" keyword if preceded by these keywords */
1828 else if (c == '(')
1830 /* Verify whether this is a valid function call (i.e. "()") operator.
1832 if (cppGetc () == ')')
1834 vStringPut (name, ' '); /* always separate operator from keyword */
1835 c = skipToNonWhite ();
1836 if (c == '(')
1837 vStringCatS (name, "()");
1839 else
1841 skipToMatch ("()");
1842 c = cppGetc ();
1845 else if (isident1 (c))
1847 /* Handle "new" and "delete" operators, and conversion functions
1848 * (per 13.3.1.1.2 [2] of the C++ spec).
1850 boolean whiteSpace = TRUE; /* default causes insertion of space */
1853 if (isspace (c))
1854 whiteSpace = TRUE;
1855 else
1857 if (whiteSpace)
1859 vStringPut (name, ' ');
1860 whiteSpace = FALSE;
1862 vStringPut (name, c);
1864 c = cppGetc ();
1865 } while (! isOneOf (c, "(;") && c != EOF);
1866 vStringTerminate (name);
1868 else if (isOneOf (c, acceptable))
1870 vStringPut (name, ' '); /* always separate operator from keyword */
1873 vStringPut (name, c);
1874 c = cppGetc ();
1875 } while (isOneOf (c, acceptable));
1876 vStringTerminate (name);
1879 cppUngetc (c);
1881 token->type = TOKEN_NAME;
1882 token->keyword = KEYWORD_NONE;
1883 processName (st);
1886 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1888 dest->type = src->type;
1889 dest->keyword = src->keyword;
1890 dest->filePosition = src->filePosition;
1891 dest->lineNumber = src->lineNumber;
1892 vStringCopy (dest->name, src->name);
1895 static void setAccess (statementInfo *const st, const accessType laccess)
1897 if (isMember (st))
1899 if (isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite))
1901 int c = skipToNonWhite ();
1903 if (c == ':')
1904 reinitStatementWithToken (st, prevToken (st, 1), FALSE);
1905 else
1906 cppUngetc (c);
1908 st->member.accessDefault = laccess;
1910 st->member.access = laccess;
1914 static void discardTypeList (tokenInfo *const token)
1916 int c = skipToNonWhite ();
1917 while (isident1 (c))
1919 readIdentifier (token, c);
1920 c = skipToNonWhite ();
1921 if (c == '.' || c == ',')
1922 c = skipToNonWhite ();
1924 cppUngetc (c);
1927 static void addParentClass (statementInfo *const st, tokenInfo *const token)
1929 if (vStringLength (token->name) > 0 &&
1930 vStringLength (st->parentClasses) > 0)
1932 vStringPut (st->parentClasses, ',');
1934 vStringCat (st->parentClasses, token->name);
1937 static void readParents (statementInfo *const st, const int qualifier)
1939 tokenInfo *const token = newToken ();
1940 tokenInfo *const parent = newToken ();
1941 int c;
1945 c = skipToNonWhite ();
1946 if (isident1 (c))
1948 readIdentifier (token, c);
1949 if (isType (token, TOKEN_NAME))
1950 vStringCat (parent->name, token->name);
1951 else
1953 addParentClass (st, parent);
1954 initToken (parent);
1957 else if (c == qualifier)
1958 vStringPut (parent->name, c);
1959 else if (c == '<')
1960 skipToMatch ("<>");
1961 else if (isType (token, TOKEN_NAME))
1963 addParentClass (st, parent);
1964 initToken (parent);
1966 } while (c != '{' && c != EOF);
1967 cppUngetc (c);
1968 deleteToken (parent);
1969 deleteToken (token);
1972 static void checkIsClassEnum (statementInfo *const st, const declType decl)
1974 if (! isLanguage (Lang_cpp) || st->declaration != DECL_ENUM)
1975 st->declaration = decl;
1978 static void processToken (tokenInfo *const token, statementInfo *const st)
1980 switch (token->keyword) /* is it a reserved word? */
1982 default: break;
1984 case KEYWORD_NONE: processName (st); break;
1985 case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
1986 case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
1987 case KEYWORD_CATCH: skipParens (); skipBraces (); break;
1988 case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
1989 case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break;
1990 case KEYWORD_CONST: st->declaration = DECL_BASE; break;
1991 case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
1992 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
1993 case KEYWORD_EXTENDS: readParents (st, '.');
1994 setToken (st, TOKEN_NONE); break;
1995 case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
1996 case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
1997 case KEYWORD_IMPLEMENTS:readParents (st, '.');
1998 setToken (st, TOKEN_NONE); break;
1999 case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
2000 case KEYWORD_INT: st->declaration = DECL_BASE; break;
2001 case KEYWORD_BOOLEAN: st->declaration = DECL_BASE; break;
2002 case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
2003 case KEYWORD_SIZE_T: st->declaration = DECL_BASE; break;
2004 case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
2005 case KEYWORD_LONG: st->declaration = DECL_BASE; break;
2006 case KEYWORD_OPERATOR: readOperator (st); break;
2007 case KEYWORD_MODULE: readPackage (st); break;
2008 case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
2009 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
2010 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
2011 case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
2012 case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
2013 case KEYWORD_STRUCT: checkIsClassEnum (st, DECL_STRUCT); break;
2014 case KEYWORD_THROWS: discardTypeList (token); break;
2015 case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
2016 case KEYWORD_UNION: st->declaration = DECL_UNION; break;
2017 case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
2018 case KEYWORD_USING: st->declaration = DECL_IGNORE; break;
2019 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
2020 case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
2021 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
2023 case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
2024 case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
2025 case KEYWORD_EVENT:
2027 if (isLanguage (Lang_csharp))
2028 st->declaration = DECL_EVENT;
2029 break;
2031 case KEYWORD_SIGNAL:
2033 if (isLanguage (Lang_vala))
2034 st->declaration = DECL_SIGNAL;
2035 break;
2037 case KEYWORD_EXTERN:
2039 if (! isLanguage (Lang_csharp) || !st->gotName)
2041 /*reinitStatement (st, FALSE);*/
2042 st->scope = SCOPE_EXTERN;
2043 st->declaration = DECL_BASE;
2045 break;
2047 case KEYWORD_STATIC:
2049 if (! isLanguage (Lang_java) && ! isLanguage (Lang_csharp) && ! isLanguage (Lang_vala))
2051 /*reinitStatement (st, FALSE);*/
2052 st->scope = SCOPE_STATIC;
2053 st->declaration = DECL_BASE;
2055 break;
2057 case KEYWORD_IF:
2058 if (isLanguage (Lang_d))
2059 { /* static if (is(typeof(__traits(getMember, a, name)) == function)) */
2060 int c = skipToNonWhite ();
2061 if (c == '(')
2062 skipToMatch ("()");
2064 break;
2069 * Parenthesis handling functions
2072 static void restartStatement (statementInfo *const st)
2074 tokenInfo *const save = newToken ();
2075 tokenInfo *token = activeToken (st);
2077 copyToken (save, token);
2078 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
2079 reinitStatement (st, FALSE);
2080 token = activeToken (st);
2081 copyToken (token, save);
2082 deleteToken (save);
2083 processToken (token, st);
2086 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
2088 * mem-initializer-list:
2089 * mem-initializer, mem-initializer-list
2091 * mem-initializer:
2092 * [::] [nested-name-spec] class-name (...)
2093 * identifier
2095 static void skipMemIntializerList (tokenInfo *const token)
2097 int c;
2101 c = skipToNonWhite ();
2102 while (isident1 (c) || c == ':')
2104 if (c != ':')
2105 readIdentifier (token, c);
2106 c = skipToNonWhite ();
2108 if (c == '<')
2110 skipToMatch ("<>");
2111 c = skipToNonWhite ();
2113 if (c == '(')
2115 skipToMatch ("()");
2116 c = skipToNonWhite ();
2118 } while (c == ',');
2119 cppUngetc (c);
2122 static void skipMacro (statementInfo *const st)
2124 tokenInfo *const prev2 = prevToken (st, 2);
2126 if (isType (prev2, TOKEN_NAME))
2127 retardToken (st);
2128 skipToMatch ("()");
2131 static boolean isDPostArgumentToken(tokenInfo *const token)
2133 switch (token->keyword)
2135 /* Note: some other keywords e.g. immutable are parsed as
2136 * KEYWORD_CONST - see initializeDParser */
2137 case KEYWORD_CONST:
2138 /* template constraint */
2139 case KEYWORD_IF:
2140 /* contracts */
2141 case KEYWORD_IN:
2142 case KEYWORD_OUT:
2143 case KEYWORD_BODY:
2144 return TRUE;
2145 default:
2146 break;
2148 /* @attributes */
2149 if (vStringValue(token->name)[0] == '@')
2150 return TRUE;
2151 return FALSE;
2154 /* Skips over characters following the parameter list. This will be either
2155 * non-ANSI style function declarations or C++ stuff. Our choices:
2157 * C (K&R):
2158 * int func ();
2159 * int func (one, two) int one; float two; {...}
2160 * C (ANSI):
2161 * int func (int one, float two);
2162 * int func (int one, float two) {...}
2163 * C++:
2164 * int foo (...) [const|volatile] [throw (...)];
2165 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2166 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2167 * catch (...) {...}
2169 static boolean skipPostArgumentStuff (statementInfo *const st,
2170 parenInfo *const info)
2172 tokenInfo *const token = activeToken (st);
2173 unsigned int parameters = info->parameterCount;
2174 unsigned int elementCount = 0;
2175 boolean restart = FALSE;
2176 boolean end = FALSE;
2177 int c = skipToNonWhite ();
2181 switch (c)
2183 case ')': break;
2184 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
2185 case '[': skipToMatch ("[]"); break;
2186 case '=': cppUngetc (c); end = TRUE; break;
2187 case '{': cppUngetc (c); end = TRUE; break;
2188 case '}': cppUngetc (c); end = TRUE; break;
2190 case '(':
2192 if (elementCount > 0)
2193 ++elementCount;
2194 skipToMatch ("()");
2195 break;
2198 case ';':
2200 if (parameters == 0 || elementCount < 2)
2202 cppUngetc (c);
2203 end = TRUE;
2205 else if (--parameters == 0)
2206 end = TRUE;
2207 break;
2210 default:
2212 if (isident1 (c))
2214 readIdentifier (token, c);
2215 if (isLanguage(Lang_d) && isDPostArgumentToken(token))
2216 token->keyword = KEYWORD_CONST;
2218 switch (token->keyword)
2220 case KEYWORD_ATTRIBUTE: skipParens (); break;
2221 case KEYWORD_THROW: skipParens (); break;
2222 case KEYWORD_CONST: break;
2223 case KEYWORD_TRY: break;
2224 case KEYWORD_VOLATILE: break;
2226 case KEYWORD_CATCH: case KEYWORD_CLASS:
2227 case KEYWORD_EXPLICIT: case KEYWORD_EXTERN:
2228 case KEYWORD_FRIEND: case KEYWORD_INLINE:
2229 case KEYWORD_MUTABLE: case KEYWORD_NAMESPACE:
2230 case KEYWORD_NEW: case KEYWORD_OPERATOR:
2231 case KEYWORD_OVERLOAD: case KEYWORD_PRIVATE:
2232 case KEYWORD_PROTECTED: case KEYWORD_PUBLIC:
2233 case KEYWORD_STATIC: case KEYWORD_TEMPLATE:
2234 case KEYWORD_TYPEDEF: case KEYWORD_TYPENAME:
2235 case KEYWORD_USING: case KEYWORD_VIRTUAL:
2236 /* Never allowed within parameter declarations.
2238 restart = TRUE;
2239 end = TRUE;
2240 break;
2242 default:
2243 if (isType (token, TOKEN_NONE))
2245 else if (info->isKnrParamList && info->parameterCount > 0)
2246 ++elementCount;
2247 else
2249 /* If we encounter any other identifier immediately
2250 * following an empty parameter list, this is almost
2251 * certainly one of those Microsoft macro "thingies"
2252 * that the automatic source code generation sticks
2253 * in. Terminate the current statement.
2255 restart = TRUE;
2256 end = TRUE;
2258 break;
2263 if (! end)
2265 c = skipToNonWhite ();
2266 if (c == EOF)
2267 end = TRUE;
2269 } while (! end);
2271 if (restart)
2272 restartStatement (st);
2273 else
2274 setToken (st, TOKEN_NONE);
2275 return (boolean) (c != EOF);
2278 static void skipJavaThrows (statementInfo *const st)
2280 tokenInfo *const token = activeToken (st);
2281 int c = skipToNonWhite ();
2283 if (isident1 (c))
2285 readIdentifier (token, c);
2286 if (token->keyword == KEYWORD_THROWS)
2290 c = skipToNonWhite ();
2291 if (isident1 (c))
2293 readIdentifier (token, c);
2294 c = skipToNonWhite ();
2296 } while (c == '.' || c == ',');
2299 cppUngetc (c);
2300 setToken (st, TOKEN_NONE);
2303 static void skipValaPostParens (statementInfo *const st)
2305 tokenInfo *const token = activeToken (st);
2306 int c = skipToNonWhite ();
2308 while (isident1 (c))
2310 readIdentifier (token, c);
2311 if (token->keyword == KEYWORD_ATTRIBUTE)
2313 /* parse contracts */
2314 skipParens ();
2315 c = skipToNonWhite ();
2317 else if (token->keyword == KEYWORD_THROWS)
2321 c = skipToNonWhite ();
2322 if (isident1 (c))
2324 readIdentifier (token, c);
2325 c = skipToNonWhite ();
2327 } while (c == '.' || c == ',');
2329 else
2330 break;
2332 cppUngetc (c);
2333 setToken (st, TOKEN_NONE);
2336 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2338 const unsigned long inputLineNumber = getInputLineNumber ();
2339 int c = skipToNonWhite ();
2341 cppUngetc (c);
2342 if (isOneOf (c, "{;,="))
2344 else if (isLanguage (Lang_java))
2345 skipJavaThrows (st);
2346 else if (isLanguage (Lang_vala))
2347 skipValaPostParens(st);
2348 else
2350 if (! skipPostArgumentStuff (st, info))
2352 verbose (
2353 "%s: confusing argument declarations beginning at line %lu\n",
2354 getInputFileName (), inputLineNumber);
2355 longjmp (Exception, (int) ExceptionFormattingError);
2360 static int parseParens (statementInfo *const st, parenInfo *const info)
2362 tokenInfo *const token = activeToken (st);
2363 unsigned int identifierCount = 0;
2364 unsigned int depth = 1;
2365 boolean firstChar = TRUE;
2366 int nextChar = '\0';
2368 info->parameterCount = 1;
2371 int c = skipToNonWhite ();
2373 switch (c)
2375 case '&':
2376 case '*':
2378 /* DEBUG_PRINT("parseParens, po++\n"); */
2379 info->isKnrParamList = FALSE;
2380 if (identifierCount == 0)
2381 info->isParamList = FALSE;
2382 initToken (token);
2383 break;
2385 case ':':
2387 info->isKnrParamList = FALSE;
2388 break;
2390 case '.':
2392 info->isNameCandidate = FALSE;
2393 info->isKnrParamList = FALSE;
2394 break;
2396 case ',':
2398 info->isNameCandidate = FALSE;
2399 if (info->isKnrParamList)
2401 ++info->parameterCount;
2402 identifierCount = 0;
2404 break;
2406 case '=':
2408 info->isKnrParamList = FALSE;
2409 info->isNameCandidate = FALSE;
2410 if (firstChar)
2412 info->isParamList = FALSE;
2413 skipMacro (st);
2414 depth = 0;
2416 break;
2418 case '[':
2420 info->isKnrParamList = FALSE;
2421 skipToMatch ("[]");
2422 break;
2424 case '<':
2426 info->isKnrParamList = FALSE;
2427 skipToMatch ("<>");
2428 break;
2430 case ')':
2432 if (firstChar)
2433 info->parameterCount = 0;
2434 --depth;
2435 break;
2437 case '(':
2439 info->isKnrParamList = FALSE;
2440 if (firstChar)
2442 info->isNameCandidate = FALSE;
2443 cppUngetc (c);
2444 skipMacro (st);
2445 depth = 0;
2447 else if (isType (token, TOKEN_PAREN_NAME))
2449 c = skipToNonWhite ();
2450 if (c == '*') /* check for function pointer */
2452 skipToMatch ("()");
2453 c = skipToNonWhite ();
2454 if (c == '(')
2455 skipToMatch ("()");
2457 else
2459 cppUngetc (c);
2460 cppUngetc ('(');
2461 info->nestedArgs = TRUE;
2464 else
2465 ++depth;
2466 break;
2469 default:
2471 if (isident1 (c))
2473 if (++identifierCount > 1)
2474 info->isKnrParamList = FALSE;
2475 readIdentifier (token, c);
2476 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2477 token->type = TOKEN_PAREN_NAME;
2478 else if (isType (token, TOKEN_KEYWORD))
2480 info->isKnrParamList = FALSE;
2481 info->isNameCandidate = FALSE;
2484 else if (isLanguage(Lang_d) && c == '!')
2485 { /* D template instantiation */
2486 info->isNameCandidate = FALSE;
2487 info->isKnrParamList = FALSE;
2489 else
2491 info->isParamList = FALSE;
2492 info->isKnrParamList = FALSE;
2493 info->isNameCandidate = FALSE;
2494 info->invalidContents = TRUE;
2496 break;
2499 firstChar = FALSE;
2500 } while (! info->nestedArgs && depth > 0 &&
2501 (info->isKnrParamList || info->isNameCandidate));
2503 if (! info->nestedArgs) while (depth > 0)
2505 skipToMatch ("()");
2506 --depth;
2508 if (st->argEndPosition == 0)
2509 st->argEndPosition = mio_tell (File.mio);
2511 if (! info->isNameCandidate)
2512 initToken (token);
2514 return nextChar;
2517 static void initParenInfo (parenInfo *const info)
2519 info->isParamList = TRUE;
2520 info->isKnrParamList = TRUE;
2521 info->isNameCandidate = TRUE;
2522 info->invalidContents = FALSE;
2523 info->nestedArgs = FALSE;
2524 info->parameterCount = 0;
2527 static void analyzeParens (statementInfo *const st)
2529 tokenInfo *const prev = prevToken (st, 1);
2531 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2533 tokenInfo *const token = activeToken (st);
2534 parenInfo info;
2535 int c;
2537 initParenInfo (&info);
2538 parseParens (st, &info);
2540 c = skipToNonWhite ();
2542 cppUngetc (c);
2543 if (info.invalidContents)
2545 reinitStatement (st, FALSE);
2547 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2548 ! st->gotParenName &&
2549 (! info.isParamList || ! st->haveQualifyingName ||
2550 c == '(' ||
2551 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2552 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2554 token->type = TOKEN_NAME;
2555 processName (st);
2556 st->gotParenName = TRUE;
2557 if (isLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME))
2559 st->declaration = DECL_FUNCTION_TEMPLATE;
2560 copyToken (st->blockName, prev);
2563 else if (! st->gotArgs && info.isParamList)
2565 st->gotArgs = TRUE;
2566 setToken (st, TOKEN_ARGS);
2567 advanceToken (st);
2568 analyzePostParens (st, &info);
2570 else
2572 setToken (st, TOKEN_NONE);
2578 * Token parsing functions
2581 static void addContext (statementInfo *const st, const tokenInfo* const token)
2583 if (isType (token, TOKEN_NAME))
2585 if (vStringLength (st->context->name) > 0)
2587 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
2588 vStringCatS (st->context->name, "::");
2589 else if (isLanguage (Lang_java) ||
2590 isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
2591 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
2592 vStringCatS (st->context->name, ".");
2594 vStringCat (st->context->name, token->name);
2595 st->context->type = TOKEN_NAME;
2599 static boolean inheritingDeclaration (declType decl)
2601 return (boolean) (decl == DECL_CLASS ||
2602 decl == DECL_STRUCT ||
2603 decl == DECL_INTERFACE);
2606 static void processColon (statementInfo *const st)
2608 int c = skipToNonWhite ();
2609 const boolean doubleColon = (boolean) (c == ':');
2611 if (doubleColon)
2613 setToken (st, TOKEN_DOUBLE_COLON);
2614 st->haveQualifyingName = FALSE;
2616 else
2618 cppUngetc (c);
2619 if (((isLanguage (Lang_cpp) &&
2620 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT)) ||
2621 isLanguage (Lang_csharp) || isLanguage (Lang_d) || isLanguage (Lang_vala)) &&
2622 inheritingDeclaration (st->declaration))
2624 readParents (st, ':');
2626 else if (parentDecl (st) == DECL_STRUCT || parentDecl (st) == DECL_CLASS)
2628 c = skipToOneOf (",;");
2629 if (c == ',')
2630 setToken (st, TOKEN_COMMA);
2631 else if (c == ';')
2632 setToken (st, TOKEN_SEMICOLON);
2634 else if (isLanguage (Lang_cpp) && st->declaration == DECL_ENUM)
2636 /* skip enum's base type */
2637 c = skipToOneOf ("{;");
2638 if (c == '{')
2639 setToken (st, TOKEN_BRACE_OPEN);
2640 else if (c == ';')
2641 setToken (st, TOKEN_SEMICOLON);
2643 else
2645 const tokenInfo *const prev = prevToken (st, 1);
2646 const tokenInfo *const prev2 = prevToken (st, 2);
2647 if (prev->keyword == KEYWORD_DEFAULT ||
2648 prev2->keyword == KEYWORD_CASE ||
2649 st->parent != NULL)
2651 reinitStatement (st, FALSE);
2657 /* Skips over any initializing value which may follow an '=' character in a
2658 * variable definition.
2660 static int skipInitializer (statementInfo *const st)
2662 boolean done = FALSE;
2663 int c;
2665 while (! done)
2667 c = skipToNonWhite ();
2669 if (c == EOF)
2670 longjmp (Exception, (int) ExceptionFormattingError);
2671 else switch (c)
2673 case ',':
2674 case ';': done = TRUE; break;
2676 case '0':
2677 if (st->implementation == IMP_VIRTUAL)
2678 st->implementation = IMP_PURE_VIRTUAL;
2679 break;
2681 case '[': skipToMatch ("[]"); break;
2682 case '(': skipToMatch ("()"); break;
2683 case '{': skipToMatch ("{}"); break;
2685 case '}':
2686 if (insideEnumBody (st))
2687 done = TRUE;
2688 else if (! isBraceFormat ())
2690 verbose ("%s: unexpected closing brace at line %lu\n",
2691 getInputFileName (), getInputLineNumber ());
2692 longjmp (Exception, (int) ExceptionBraceFormattingError);
2694 break;
2696 default: break;
2699 return c;
2702 static void processInitializer (statementInfo *const st)
2704 const boolean inEnumBody = insideEnumBody (st);
2705 const int c = skipInitializer (st);
2707 if (c == ';')
2708 setToken (st, TOKEN_SEMICOLON);
2709 else if (c == ',')
2710 setToken (st, TOKEN_COMMA);
2711 else if (c == '}' && inEnumBody)
2713 cppUngetc (c);
2714 setToken (st, TOKEN_COMMA);
2716 if (st->scope == SCOPE_EXTERN)
2717 st->scope = SCOPE_GLOBAL;
2720 static void parseIdentifier (statementInfo *const st, const int c)
2722 tokenInfo *const token = activeToken (st);
2724 readIdentifier (token, c);
2725 if (! isType (token, TOKEN_NONE))
2726 processToken (token, st);
2729 static void parseGeneralToken (statementInfo *const st, const int c)
2731 const tokenInfo *const prev = prevToken (st, 1);
2733 if (isident1(c))
2735 parseIdentifier (st, c);
2736 if (isType (st->context, TOKEN_NAME) &&
2737 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2739 initToken (st->context);
2742 else if (isExternCDecl (st, c))
2744 st->declaration = DECL_NOMANGLE;
2745 st->scope = SCOPE_GLOBAL;
2749 /* Reads characters from the pre-processor and assembles tokens, setting
2750 * the current statement state.
2752 static void nextToken (statementInfo *const st)
2754 int c;
2755 tokenInfo *token = activeToken (st);
2758 c = skipToNonWhite();
2759 switch (c)
2761 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2762 case '(': analyzeParens (st); token = activeToken (st); break;
2763 case '*': setToken (st, TOKEN_STAR); break;
2764 case ',': setToken (st, TOKEN_COMMA); break;
2765 case ':': processColon (st); break;
2766 case ';': setToken (st, TOKEN_SEMICOLON); break;
2767 case '<': skipToMatch ("<>"); break;
2768 case '=': processInitializer (st); break;
2769 case '[':
2770 /* Hack for Vala: [..] can be a function attribute.
2771 * Seems not to have bad side effects, but have to test it more. */
2772 if (!isLanguage (Lang_vala))
2773 setToken (st, TOKEN_ARRAY);
2774 skipToMatch ("[]");
2775 break;
2776 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2777 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2778 default: parseGeneralToken (st, c); break;
2780 } while (isType (token, TOKEN_NONE));
2782 /* We want to know about non-keyword variable types */
2783 if (TOKEN_NONE == st->firstToken->type)
2785 if ((TOKEN_NAME == token->type) || isDataTypeKeyword(token))
2786 copyToken(st->firstToken, token);
2791 * Scanning support functions
2793 static unsigned int contextual_fake_count = 0;
2794 static statementInfo *CurrentStatement = NULL;
2796 static statementInfo *newStatement (statementInfo *const parent)
2798 statementInfo *const st = xMalloc (1, statementInfo);
2799 unsigned int i;
2801 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2802 st->token [i] = newToken ();
2804 st->context = newToken ();
2805 st->blockName = newToken ();
2806 st->parentClasses = vStringNew ();
2807 st->firstToken = newToken();
2809 initStatement (st, parent);
2810 CurrentStatement = st;
2812 return st;
2815 static void deleteStatement (void)
2817 statementInfo *const st = CurrentStatement;
2818 statementInfo *const parent = st->parent;
2819 unsigned int i;
2821 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2823 deleteToken(st->token[i]); st->token[i] = NULL;
2825 deleteToken(st->blockName); st->blockName = NULL;
2826 deleteToken(st->context); st->context = NULL;
2827 vStringDelete(st->parentClasses); st->parentClasses = NULL;
2828 deleteToken(st->firstToken);
2829 eFree (st);
2830 CurrentStatement = parent;
2833 static void deleteAllStatements (void)
2835 while (CurrentStatement != NULL)
2836 deleteStatement ();
2839 static boolean isStatementEnd (const statementInfo *const st)
2841 const tokenInfo *const token = activeToken (st);
2842 boolean isEnd;
2844 if (isType (token, TOKEN_SEMICOLON))
2845 isEnd = TRUE;
2846 else if (isType (token, TOKEN_BRACE_CLOSE))
2847 /* Java, D, C#, Vala do not require semicolons to end a block. Neither do
2848 * C++ namespaces. All other blocks require a semicolon to terminate them.
2850 isEnd = (boolean) (isLanguage (Lang_java) || isLanguage (Lang_d) ||
2851 isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
2852 ! isContextualStatement (st));
2853 else
2854 isEnd = FALSE;
2856 return isEnd;
2859 static void checkStatementEnd (statementInfo *const st)
2861 const tokenInfo *const token = activeToken (st);
2862 boolean comma = isType (token, TOKEN_COMMA);
2864 if (comma || isStatementEnd (st))
2866 reinitStatementWithToken (st, activeToken (st), comma);
2868 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2869 cppEndStatement ();
2871 else
2873 cppBeginStatement ();
2874 advanceToken (st);
2878 static void nest (statementInfo *const st, const unsigned int nestLevel)
2880 switch (st->declaration)
2882 case DECL_CLASS:
2883 case DECL_ENUM:
2884 case DECL_INTERFACE:
2885 case DECL_NAMESPACE:
2886 case DECL_NOMANGLE:
2887 case DECL_STRUCT:
2888 case DECL_UNION:
2889 createTags (nestLevel, st);
2890 break;
2891 default:
2892 skipToMatch ("{}");
2893 break;
2895 advanceToken (st);
2896 setToken (st, TOKEN_BRACE_CLOSE);
2899 static void tagCheck (statementInfo *const st)
2901 const tokenInfo *const token = activeToken (st);
2902 const tokenInfo *const prev = prevToken (st, 1);
2903 const tokenInfo *const prev2 = prevToken (st, 2);
2905 switch (token->type)
2907 case TOKEN_NAME:
2909 if (insideEnumBody (st))
2910 qualifyEnumeratorTag (st, token);
2911 break;
2913 #if 0
2914 case TOKEN_PACKAGE:
2916 if (st->haveQualifyingName)
2917 makeTag (token, st, FALSE, TAG_PACKAGE);
2918 break;
2920 #endif
2921 case TOKEN_BRACE_OPEN:
2923 if (isType (prev, TOKEN_ARGS))
2925 if (st->declaration == DECL_FUNCTION_TEMPLATE)
2926 qualifyFunctionTag (st, st->blockName);
2927 else if (st->haveQualifyingName)
2929 if (isType (prev2, TOKEN_NAME))
2930 copyToken (st->blockName, prev2);
2931 /* D structure templates */
2932 if (isLanguage (Lang_d) &&
2933 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT ||
2934 st->declaration == DECL_INTERFACE || st->declaration == DECL_NAMESPACE))
2935 qualifyBlockTag (st, prev2);
2936 else
2938 st->declaration = DECL_FUNCTION;
2939 qualifyFunctionTag (st, prev2);
2943 else if (isContextualStatement (st))
2945 tokenInfo *name_token = (tokenInfo *)prev;
2946 boolean free_name_token = FALSE;
2948 if (isType (name_token, TOKEN_NAME))
2950 if (!isLanguage (Lang_vala))
2951 copyToken (st->blockName, name_token);
2952 else
2954 switch (st->declaration)
2956 case DECL_CLASS:
2957 case DECL_ENUM:
2958 case DECL_INTERFACE:
2959 case DECL_NAMESPACE:
2960 case DECL_STRUCT:
2961 copyToken (st->blockName, name_token);
2962 break;
2964 /* anything else can be a property */
2965 default:
2966 /* makeTag (prev, st, FALSE, TAG_PROPERTY); */
2967 /* FIXME: temporary hack to get properties shown */
2968 makeTag (prev, st, FALSE, TAG_FIELD);
2969 break;
2973 /* C++ 11 allows class <name> final { ... } */
2974 else if (isLanguage (Lang_cpp) && isType (prev, TOKEN_KEYWORD) &&
2975 prev->keyword == KEYWORD_FINAL && isType(prev2, TOKEN_NAME))
2977 name_token = (tokenInfo *)prev2;
2978 copyToken (st->blockName, name_token);
2980 else if (isLanguage (Lang_csharp))
2981 makeTag (prev, st, FALSE, TAG_PROPERTY);
2982 else
2984 tokenInfo *contextual_token = (tokenInfo *)prev;
2985 if(isContextualKeyword (contextual_token))
2987 char buffer[64];
2989 name_token = newToken ();
2990 free_name_token = TRUE;
2991 copyToken (name_token, contextual_token);
2993 sprintf(buffer, "anon_%s_%d", name_token->name->buffer, contextual_fake_count++);
2994 vStringClear(name_token->name);
2995 vStringCatS(name_token->name, buffer);
2997 name_token->type = TOKEN_NAME;
2998 name_token->keyword = KEYWORD_NONE;
3000 advanceToken (st);
3001 contextual_token = activeToken (st);
3002 copyToken (contextual_token, token);
3003 copyToken ((tokenInfo *const)token, name_token);
3004 copyToken (st->blockName, name_token);
3005 copyToken (st->firstToken, name_token);
3008 qualifyBlockTag (st, name_token);
3009 if (free_name_token)
3010 deleteToken (name_token);
3012 break;
3014 case TOKEN_ARRAY:
3015 case TOKEN_SEMICOLON:
3016 case TOKEN_COMMA:
3018 if (insideEnumBody (st))
3020 else if (isType (prev, TOKEN_NAME))
3022 if (isContextualKeyword (prev2))
3023 makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
3024 else
3025 qualifyVariableTag (st, prev);
3027 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
3029 qualifyFunctionDeclTag (st, prev2);
3031 break;
3033 default:
3034 break;
3038 /* Parses the current file and decides whether to write out and tags that
3039 * are discovered.
3041 static void createTags (const unsigned int nestLevel,
3042 statementInfo *const parent)
3044 statementInfo *const st = newStatement (parent);
3046 DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
3047 while (TRUE)
3049 tokenInfo *token;
3051 nextToken (st);
3053 token = activeToken (st);
3055 if (isType (token, TOKEN_BRACE_CLOSE))
3057 if (nestLevel > 0)
3058 break;
3059 else
3061 verbose ("%s: unexpected closing brace at line %lu\n",
3062 getInputFileName (), getInputLineNumber ());
3063 longjmp (Exception, (int) ExceptionBraceFormattingError);
3066 else if (isType (token, TOKEN_DOUBLE_COLON))
3068 addContext (st, prevToken (st, 1));
3069 advanceToken (st);
3071 else
3073 tagCheck (st);/* this can add new token */
3074 if (isType (activeToken (st), TOKEN_BRACE_OPEN))
3075 nest (st, nestLevel + 1);
3076 checkStatementEnd (st);
3079 deleteStatement ();
3080 DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
3083 static boolean findCTags (const unsigned int passCount)
3085 exception_t exception;
3086 boolean retry;
3088 contextual_fake_count = 0;
3090 Assert (passCount < 3);
3091 cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
3093 exception = (exception_t) setjmp (Exception);
3094 retry = FALSE;
3096 if (exception == ExceptionNone)
3098 createTags (0, NULL);
3100 else
3102 deleteAllStatements ();
3103 if (exception == ExceptionBraceFormattingError && passCount == 1)
3105 retry = TRUE;
3106 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3107 getInputFileName ());
3110 cppTerminate ();
3111 return retry;
3114 static void buildKeywordHash (const langType language, unsigned int idx)
3116 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
3117 size_t i;
3118 for (i = 0 ; i < count ; ++i)
3120 const keywordDesc* const p = &KeywordTable [i];
3121 if (p->isValid [idx])
3122 addKeyword (p->name, language, (int) p->id);
3126 static void initializeCParser (const langType language)
3128 Lang_c = language;
3129 buildKeywordHash (language, 0);
3132 static void initializeCppParser (const langType language)
3134 Lang_cpp = language;
3135 buildKeywordHash (language, 1);
3138 static void initializeJavaParser (const langType language)
3140 Lang_java = language;
3141 buildKeywordHash (language, 3);
3144 static void initializeDParser (const langType language)
3146 /* treat these like const - some are for parsing like const(Type), some are just
3147 * function attributes */
3148 const char *const_aliases[] = {"immutable", "nothrow", "pure", "shared", NULL};
3149 const char **s;
3151 Lang_d = language;
3152 buildKeywordHash (language, 6);
3154 for (s = const_aliases; *s != NULL; s++)
3156 addKeyword (*s, language, KEYWORD_CONST);
3158 /* other keyword aliases */
3159 addKeyword ("alias", language, KEYWORD_TYPEDEF);
3160 /* skip 'static assert(...)' like 'static if (...)' */
3161 addKeyword ("assert", language, KEYWORD_IF);
3162 addKeyword ("unittest", language, KEYWORD_BODY); /* ignore */
3163 addKeyword ("version", language, KEYWORD_NAMESPACE); /* parse block */
3166 static void initializeGLSLParser (const langType language)
3168 Lang_glsl = language;
3169 buildKeywordHash (language, 0); /* C keywords */
3172 static void initializeFeriteParser (const langType language)
3174 Lang_ferite = language;
3175 buildKeywordHash (language, 1); /* C++ keywords */
3178 static void initializeCsharpParser (const langType language)
3180 Lang_csharp = language;
3181 buildKeywordHash (language, 2);
3184 static void initializeValaParser (const langType language)
3186 Lang_vala = language;
3187 buildKeywordHash (language, 5);
3189 /* keyword aliases */
3190 addKeyword ("ensures", language, KEYWORD_ATTRIBUTE); /* ignore */
3191 addKeyword ("errordomain", language, KEYWORD_ENUM); /* looks like enum */
3192 addKeyword ("requires", language, KEYWORD_ATTRIBUTE); /* ignore */
3195 extern parserDefinition* CParser (void)
3197 static const char *const extensions [] = { "c", "pc", "sc", NULL };
3198 parserDefinition* def = parserNew ("C");
3199 def->kinds = CKinds;
3200 def->kindCount = KIND_COUNT (CKinds);
3201 def->extensions = extensions;
3202 def->parser2 = findCTags;
3203 def->initialize = initializeCParser;
3204 return def;
3207 extern parserDefinition* CppParser (void)
3209 static const char *const extensions [] = {
3210 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3211 "i",
3212 #ifndef CASE_INSENSITIVE_FILENAMES
3213 "C", "H",
3214 #endif
3215 NULL
3217 parserDefinition* def = parserNew ("C++");
3218 def->kinds = CKinds;
3219 def->kindCount = KIND_COUNT (CKinds);
3220 def->extensions = extensions;
3221 def->parser2 = findCTags;
3222 def->initialize = initializeCppParser;
3223 return def;
3226 extern parserDefinition* JavaParser (void)
3228 static const char *const extensions [] = { "java", NULL };
3229 parserDefinition* def = parserNew ("Java");
3230 def->kinds = JavaKinds;
3231 def->kindCount = KIND_COUNT (JavaKinds);
3232 def->extensions = extensions;
3233 def->parser2 = findCTags;
3234 def->initialize = initializeJavaParser;
3235 return def;
3238 extern parserDefinition* DParser (void)
3240 static const char *const extensions [] = { "d", "di", NULL };
3241 parserDefinition* def = parserNew ("D");
3242 def->kinds = DKinds;
3243 def->kindCount = KIND_COUNT (DKinds);
3244 def->extensions = extensions;
3245 def->parser2 = findCTags;
3246 def->initialize = initializeDParser;
3247 return def;
3250 extern parserDefinition* GLSLParser (void)
3252 static const char *const extensions [] = { "glsl", "frag", "vert", NULL };
3253 parserDefinition* def = parserNew ("GLSL");
3254 def->kinds = CKinds;
3255 def->kindCount = KIND_COUNT (CKinds);
3256 def->extensions = extensions;
3257 def->parser2 = findCTags;
3258 def->initialize = initializeGLSLParser;
3259 return def;
3262 extern parserDefinition* FeriteParser (void)
3264 static const char *const extensions [] = { "fe", NULL };
3265 parserDefinition* def = parserNew ("Ferite");
3266 def->kinds = CKinds;
3267 def->kindCount = KIND_COUNT (CKinds);
3268 def->extensions = extensions;
3269 def->parser2 = findCTags;
3270 def->initialize = initializeFeriteParser;
3271 return def;
3274 extern parserDefinition* CsharpParser (void)
3276 static const char *const extensions [] = { "cs", NULL };
3277 parserDefinition* def = parserNew ("C#");
3278 def->kinds = CsharpKinds;
3279 def->kindCount = KIND_COUNT (CsharpKinds);
3280 def->extensions = extensions;
3281 def->parser2 = findCTags;
3282 def->initialize = initializeCsharpParser;
3283 return def;
3286 extern parserDefinition* ValaParser (void)
3288 static const char *const extensions [] = { "vala", NULL };
3289 parserDefinition* def = parserNew ("Vala");
3290 def->kinds = ValaKinds;
3291 def->kindCount = KIND_COUNT (ValaKinds);
3292 def->extensions = extensions;
3293 def->parser2 = findCTags;
3294 def->initialize = initializeValaParser;
3295 return def;
3297 /* vi:set tabstop=8 shiftwidth=4: */