Update HACKING for changed doc generation instructions
[geany-mirror.git] / tagmanager / ctags / c.c
blob99070e3edf9afd258d7c99ddd280720b00a127ab
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,
86 KEYWORD_STATIC_ASSERT, KEYWORD_STRING,
87 KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
88 KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
89 KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
90 KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
91 KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
92 KEYWORD_USING,
93 KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
94 KEYWORD_WCHAR_T, KEYWORD_WEAK, KEYWORD_WHILE
95 } keywordId;
97 /* Used to determine whether keyword is valid for the current language and
98 * what its ID is.
100 typedef struct sKeywordDesc
102 const char *name;
103 keywordId id;
104 short isValid [7]; /* indicates languages for which kw is valid */
105 } keywordDesc;
107 /* Used for reporting the type of object parsed by nextToken ().
109 typedef enum eTokenType
111 TOKEN_NONE, /* none */
112 TOKEN_ARGS, /* a parenthetical pair and its contents */
113 TOKEN_BRACE_CLOSE,
114 TOKEN_BRACE_OPEN,
115 TOKEN_COMMA, /* the comma character */
116 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
117 TOKEN_KEYWORD,
118 TOKEN_NAME, /* an unknown name */
119 TOKEN_PACKAGE, /* a Java package name */
120 TOKEN_PAREN_NAME, /* a single name in parentheses */
121 TOKEN_SEMICOLON, /* the semicolon character */
122 TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
123 TOKEN_STAR, /* pointer detection */
124 TOKEN_ARRAY, /* array detection */
125 TOKEN_COUNT
126 } tokenType;
128 /* This describes the scoping of the current statement.
130 typedef enum eTagScope
132 SCOPE_GLOBAL, /* no storage class specified */
133 SCOPE_STATIC, /* static storage class */
134 SCOPE_EXTERN, /* external storage class */
135 SCOPE_FRIEND, /* declares access only */
136 SCOPE_TYPEDEF, /* scoping depends upon context */
137 SCOPE_COUNT
138 } tagScope;
140 typedef enum eDeclaration
142 DECL_NONE,
143 DECL_BASE, /* base type (default) */
144 DECL_CLASS,
145 DECL_ENUM,
146 DECL_EVENT,
147 DECL_SIGNAL,
148 DECL_FUNCTION,
149 DECL_FUNCTION_TEMPLATE,
150 DECL_IGNORE, /* non-taggable "declaration" */
151 DECL_INTERFACE,
152 DECL_MODULE,
153 DECL_NAMESPACE,
154 DECL_NOMANGLE, /* C++ name demangling block */
155 DECL_PACKAGE,
156 DECL_STRUCT,
157 DECL_UNION,
158 DECL_COUNT
159 } declType;
161 typedef enum eVisibilityType
163 ACCESS_UNDEFINED,
164 ACCESS_PRIVATE,
165 ACCESS_PROTECTED,
166 ACCESS_PUBLIC,
167 ACCESS_DEFAULT, /* Java-specific */
168 ACCESS_COUNT
169 } accessType;
171 /* Information about the parent class of a member (if any).
173 typedef struct sMemberInfo
175 accessType access; /* access of current statement */
176 accessType accessDefault; /* access default for current statement */
177 } memberInfo;
179 typedef struct sTokenInfo
181 tokenType type;
182 keywordId keyword;
183 vString* name; /* the name of the token */
184 unsigned long lineNumber; /* line number of tag */
185 MIOPos filePosition; /* file position of line containing name */
186 } tokenInfo;
188 typedef enum eImplementation
190 IMP_DEFAULT,
191 IMP_ABSTRACT,
192 IMP_VIRTUAL,
193 IMP_PURE_VIRTUAL,
194 IMP_COUNT
195 } impType;
197 /* Describes the statement currently undergoing analysis.
199 typedef struct sStatementInfo
201 tagScope scope;
202 declType declaration; /* specifier associated with TOKEN_SPEC */
203 boolean gotName; /* was a name parsed yet? */
204 boolean haveQualifyingName; /* do we have a name we are considering? */
205 boolean gotParenName; /* was a name inside parentheses parsed yet? */
206 boolean gotArgs; /* was a list of parameters parsed yet? */
207 unsigned int nSemicolons; /* how many semicolons did we see in that statement */
208 impType implementation; /* abstract or concrete implementation? */
209 unsigned int tokenIndex; /* currently active token */
210 tokenInfo* token [((int) NumTokens)];
211 tokenInfo* context; /* accumulated scope of current statement */
212 tokenInfo* blockName; /* name of current block */
213 memberInfo member; /* information regarding parent class/struct */
214 vString* parentClasses; /* parent classes */
215 struct sStatementInfo *parent; /* statement we are nested within */
216 long argEndPosition; /* Position where argument list ended */
217 tokenInfo* firstToken; /* First token in the statement */
218 } statementInfo;
220 /* Describes the type of tag being generated.
222 typedef enum eTagType
224 TAG_UNDEFINED,
225 TAG_CLASS, /* class name */
226 TAG_ENUM, /* enumeration name */
227 TAG_ENUMERATOR, /* enumerator (enumeration value) */
228 TAG_FIELD, /* field (Java) */
229 TAG_FUNCTION, /* function definition */
230 TAG_INTERFACE, /* interface declaration */
231 TAG_MEMBER, /* structure, class or interface member */
232 TAG_METHOD, /* method declaration */
233 TAG_NAMESPACE, /* namespace name */
234 TAG_PACKAGE, /* package name */
235 TAG_PROTOTYPE, /* function prototype or declaration */
236 TAG_STRUCT, /* structure name */
237 TAG_TYPEDEF, /* typedef name */
238 TAG_UNION, /* union name */
239 TAG_VARIABLE, /* variable definition */
240 TAG_EXTERN_VAR, /* external variable declaration */
241 TAG_MACRO, /* #define s */
242 TAG_EVENT, /* event */
243 TAG_SIGNAL, /* signal */
244 TAG_LOCAL, /* local variable definition */
245 TAG_PROPERTY, /* property name */
246 TAG_COUNT /* must be last */
247 } tagType;
249 typedef struct sParenInfo
251 boolean isParamList;
252 boolean isKnrParamList;
253 boolean isNameCandidate;
254 boolean invalidContents;
255 boolean nestedArgs;
256 unsigned int parameterCount;
257 } parenInfo;
260 * DATA DEFINITIONS
263 static jmp_buf Exception;
265 static langType Lang_c;
266 static langType Lang_cpp;
267 static langType Lang_csharp;
268 static langType Lang_java;
269 static langType Lang_d;
270 static langType Lang_glsl;
271 static langType Lang_ferite;
272 static langType Lang_vala;
274 /* Used to index into the CKinds table. */
275 typedef enum
277 CK_UNDEFINED = -1,
278 CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
279 CK_ENUMERATION, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
280 CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
281 CK_EXTERN_VARIABLE
282 } cKind;
284 static kindOption CKinds [] = {
285 { TRUE, 'c', "class", "classes"},
286 { TRUE, 'd', "macro", "macro definitions"},
287 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
288 { TRUE, 'f', "function", "function definitions"},
289 { TRUE, 'g', "enum", "enumeration names"},
290 { TRUE, 'm', "member", "class, struct, and union members"},
291 { TRUE, 'n', "namespace", "namespaces"},
292 { FALSE, 'p', "prototype", "function prototypes"},
293 { TRUE, 's', "struct", "structure names"},
294 { TRUE, 't', "typedef", "typedefs"},
295 { TRUE, 'u', "union", "union names"},
296 { TRUE, 'v', "variable", "variable definitions"},
297 { FALSE, 'x', "externvar", "external variable declarations"},
300 /* Used to index into the DKinds table. */
301 typedef enum
303 DK_UNDEFINED = -1,
304 DK_CLASS, DK_ENUMERATOR, DK_FUNCTION,
305 DK_ENUMERATION, DK_INTERFACE, DK_MEMBER, DK_NAMESPACE, DK_PROTOTYPE,
306 DK_STRUCT, DK_TYPEDEF, DK_UNION, DK_VARIABLE,
307 DK_EXTERN_VARIABLE
308 } dKind;
310 static kindOption DKinds [] = {
311 { TRUE, 'c', "class", "classes"},
312 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
313 { TRUE, 'f', "function", "function definitions"},
314 { TRUE, 'g', "enum", "enumeration names"},
315 { TRUE, 'i', "interface", "interfaces"},
316 { TRUE, 'm', "member", "class, struct, and union members"},
317 { TRUE, 'n', "namespace", "namespaces"},
318 { FALSE, 'p', "prototype", "function prototypes"},
319 { TRUE, 's', "struct", "structure names"},
320 { TRUE, 't', "typedef", "typedefs"},
321 { TRUE, 'u', "union", "union names"},
322 { TRUE, 'v', "variable", "variable definitions"},
323 { FALSE, 'x', "externvar", "external variable declarations"},
326 /* Used to index into the JavaKinds table. */
327 typedef enum
329 JK_UNDEFINED = -1,
330 JK_CLASS, JK_FIELD, JK_INTERFACE, JK_METHOD,
331 JK_PACKAGE, JK_ENUMERATOR, JK_ENUMERATION
332 } javaKind;
334 static kindOption JavaKinds [] = {
335 { TRUE, 'c', "class", "classes"},
336 { TRUE, 'f', "field", "fields"},
337 { TRUE, 'i', "interface", "interfaces"},
338 { TRUE, 'm', "method", "methods"},
339 { TRUE, 'p', "package", "packages"},
340 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
341 { TRUE, 'g', "enum", "enumeration names"},
344 typedef enum
346 CSK_UNDEFINED = -1,
347 CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
348 CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
349 CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
350 } csharpKind;
352 static kindOption CsharpKinds [] = {
353 { TRUE, 'c', "class", "classes"},
354 { TRUE, 'd', "macro", "macro definitions"},
355 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
356 { TRUE, 'E', "event", "events"},
357 { TRUE, 'f', "field", "fields"},
358 { TRUE, 'g', "enum", "enumeration names"},
359 { TRUE, 'i', "interface", "interfaces"},
360 { FALSE, 'l', "local", "local variables"},
361 { TRUE, 'm', "method", "methods"},
362 { TRUE, 'n', "namespace", "namespaces"},
363 { TRUE, 'p', "property", "properties"},
364 { TRUE, 's', "struct", "structure names"},
365 { TRUE, 't', "typedef", "typedefs"},
368 typedef enum {
369 VK_UNDEFINED = -1,
370 VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FIELD,
371 VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_METHOD,
372 VK_NAMESPACE, VK_PROPERTY, VK_SIGNAL, VK_STRUCT
373 } valaKind;
375 static kindOption ValaKinds [] = {
376 { TRUE, 'c', "class", "classes"},
377 { TRUE, 'd', "macro", "macro definitions"},
378 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
379 { TRUE, 'f', "field", "fields"},
380 { TRUE, 'g', "enum", "enumeration names"},
381 { TRUE, 'i', "interface", "interfaces"},
382 { FALSE, 'l', "local", "local variables"},
383 { TRUE, 'm', "method", "methods"},
384 { TRUE, 'n', "namespace", "namespaces"},
385 { TRUE, 'p', "property", "properties"},
386 { TRUE, 'S', "signal", "signals"},
387 { TRUE, 's', "struct", "structure names"},
390 /* Note: some keyword aliases are added in initializeDParser, initializeValaParser */
391 static const keywordDesc KeywordTable [] = {
392 /* C++ */
393 /* ANSI C | C# Java */
394 /* | | | | Vera */
395 /* | | | | | Vala */
396 /* | | | | | | D */
397 /* keyword keyword ID | | | | | | | */
398 { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0, 0, 1 } },
399 { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0, 1, 1 } },
400 { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
401 { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
402 { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1, 0, 0 } },
403 { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1, 0, 0 } },
404 { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1, 0, 0 } },
405 { "body", KEYWORD_BODY, { 0, 0, 0, 0, 0, 0, 1 } },
406 { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0, 0, 0 } },
407 { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0, 0, 1 } },
408 { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0, 1, 1 } },
409 { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0, 1, 1 } },
410 { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0, 1, 1 } },
411 { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1, 1, 1 } },
412 { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0, 1, 1 } },
413 { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1, 0, 0 } },
414 { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1, 0, 0 } },
415 { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1, 0, 0 } },
416 { "do", KEYWORD_DO, { 1, 1, 1, 1, 0, 1, 1 } },
417 { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0, 1, 1 } },
418 { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0, 1, 1 } },
419 { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0, 1, 1 } },
420 { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0, 1, 1 } },
421 { "else", KEYWORD_ELSE, { 1, 1, 0, 1, 0, 1, 1 } },
422 { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1, 1, 1 } },
423 { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1, 0, 0 } },
424 { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0, 0, 1 } },
425 { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1, 0, 0 } },
426 { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1, 1, 0 } },
427 { "extern", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
428 { "final", KEYWORD_FINAL, { 0, 1, 0, 1, 0, 0, 1 } },
429 { "finally", KEYWORD_FINALLY, { 0, 0, 0, 0, 0, 1, 1 } },
430 { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0, 1, 1 } },
431 { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0, 1, 1 } },
432 { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0, 0, 0 } },
433 { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1, 0, 1 } },
434 { "get", KEYWORD_GET, { 0, 0, 0, 0, 0, 1, 0 } },
435 { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0, 1, 1 } },
436 { "if", KEYWORD_IF, { 1, 1, 1, 1, 0, 1, 1 } },
437 { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0, 0, 0 } },
438 { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0, 0, 1 } },
439 { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0, 1, 0 } },
440 { "in", KEYWORD_IN, { 0, 0, 0, 0, 0, 0, 1 } },
441 { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1, 0, 0 } },
442 { "inout", KEYWORD_CONST, { 0, 0, 0, 0, 0, 0, 1 } }, /* treat like const */
443 { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1, 0, 0 } },
444 { "int", KEYWORD_INT, { 1, 1, 1, 1, 0, 1, 1 } },
445 { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1, 0, 0 } },
446 { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1, 1, 1 } },
447 { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0, 0, 0 } },
448 { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1, 0, 0 } },
449 { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0, 1, 1 } },
450 { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
451 { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
452 { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
453 { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
454 { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0, 0, 0 } },
455 { "module", KEYWORD_MODULE, { 0, 0, 0, 0, 0, 0, 1 } },
456 { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0, 1, 0 } },
457 { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0, 0, 0 } },
458 { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0, 1, 1 } },
459 { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1, 0, 0 } },
460 { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0, 0, 0 } },
461 { "out", KEYWORD_OUT, { 0, 0, 0, 0, 0, 1, 1 } },
462 { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1, 0, 0 } },
463 { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0, 0, 0 } },
464 { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0, 1, 1 } },
465 { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0, 0, 1 } },
466 { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1, 0, 0 } },
467 { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1, 0, 0 } },
468 { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0, 1, 1 } },
469 { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1, 0, 0 } },
470 { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1, 1, 1 } },
471 { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1, 1, 1 } },
472 { "ref", KEYWORD_REF, { 0, 0, 0, 0, 0, 1, 1 } },
473 { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0, 0, 0 } },
474 { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0, 1, 1 } },
475 { "set", KEYWORD_SET, { 0, 0, 0, 0, 0, 1, 0 } },
476 { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1, 0, 0 } },
477 { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0, 1, 1 } },
478 { "signal", KEYWORD_SIGNAL, { 0, 0, 0, 0, 0, 1, 0 } },
479 { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0, 0, 0 } },
480 { "size_t", KEYWORD_SIZE_T, { 1, 1, 0, 0, 0, 1, 1 } },
481 { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
482 { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1, 1, 1 } },
483 { "static_assert", KEYWORD_STATIC_ASSERT, { 0, 1, 0, 0, 0, 0, 0 } },
484 { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1, 1, 0 } },
485 { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0, 1, 1 } },
486 { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0, 1, 1 } },
487 { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0, 0, 1 } },
488 { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1, 0, 0 } },
489 { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0, 0, 0 } },
490 { "template", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
491 { "this", KEYWORD_THIS, { 0, 0, 1, 1, 0, 1, 0 } }, /* 0 to allow D ctor tags */
492 { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0, 1, 1 } },
493 { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0, 1, 0 } },
494 { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
495 { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1, 0, 0 } },
496 { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0, 0, 0 } },
497 { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0, 1, 1 } },
498 { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1, 0, 1 } },
499 { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0, 0, 0 } },
500 { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0, 1, 1 } },
501 { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0, 1, 1 } },
502 { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0, 0, 1 } },
503 { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0, 0, 1 } },
504 { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0, 1, 1 } },
505 { "using", KEYWORD_USING, { 0, 1, 1, 0, 0, 1, 0 } },
506 { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1, 1, 0 } },
507 { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1, 1, 1 } },
508 { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0, 0, 1 } },
509 { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0, 0, 1 } },
510 { "weak", KEYWORD_WEAK, { 0, 0, 0, 0, 0, 1, 0 } },
511 { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0, 1, 1 } }
516 * FUNCTION PROTOTYPES
518 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
519 static void copyToken (tokenInfo *const dest, const tokenInfo *const src);
520 static const char *getVarType (const statementInfo *const st);
523 * FUNCTION DEFINITIONS
526 /* Debugging functions added by Biswa */
527 #if defined(DEBUG_C) && DEBUG_C
528 static char *tokenTypeName[] = {
529 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
530 "package", "paren-name", "';'", "spec", "*", "[]", "count"
533 static char *tagScopeNames[] = {
534 "global", "static", "extern", "friend", "typedef", "count"};
536 static char *declTypeNames[] = {
537 "none", "base", "class", "enum", "function", "ignore", "interface",
538 "namespace", "nomangle", "package", "struct", "union", "count"};
540 static char *impTypeNames[] = {
541 "default", "abstract", "virtual", "pure-virtual", "count"};
543 void printToken(const tokenInfo *const token)
545 fprintf(stderr, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName[token->type],
546 token->keyword, vStringValue(token->name));
549 void printTagEntry(const tagEntryInfo *tag)
551 fprintf(stderr, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag->name,
552 tag->kindName, tag->extensionFields.implementation, tag->extensionFields.scope[1],
553 tag->extensionFields.varType);
556 void printStatement(const statementInfo *const statement)
558 int i;
559 statementInfo *st = (statementInfo *) statement;
560 while (NULL != st)
562 fprintf(stderr, "Statement Info:\n------------------------\n");
563 fprintf(stderr, "scope: %s, decl: %s, impl: %s\n", tagScopeNames[st->scope],
564 declTypeNames[st->declaration], impTypeNames[st->implementation]);
565 for (i=0; i < NumTokens; ++i)
567 fprintf(stderr, "Token %d %s: ", i, (i == st->tokenIndex)?"(current)":"");
568 printToken(st->token[i]);
570 fprintf(stderr, "Context: ");
571 printToken(st->context);
572 fprintf(stderr, "Block: ");
573 printToken(st->blockName);
574 fprintf(stderr, "Parent classes: %s\n", vStringValue(st->parentClasses));
575 fprintf(stderr, "First token: ");
576 printToken(st->firstToken);
577 if (NULL != st->parent)
578 fprintf(stderr, "Printing Parent:\n");
579 st = st->parent;
581 fprintf(stderr, "-----------------------------------------------\n");
583 #endif
585 extern boolean includingDefineTags (void)
587 if (isLanguage(Lang_c) ||
588 isLanguage(Lang_cpp) ||
589 isLanguage(Lang_csharp) ||
590 isLanguage(Lang_ferite) ||
591 isLanguage(Lang_glsl) ||
592 isLanguage(Lang_vala))
593 return CKinds [CK_DEFINE].enabled;
595 return FALSE;
599 * Token management
602 static void initToken (tokenInfo* const token)
604 token->type = TOKEN_NONE;
605 token->keyword = KEYWORD_NONE;
606 token->lineNumber = getSourceLineNumber();
607 token->filePosition = getInputFilePosition();
608 vStringClear(token->name);
611 static void advanceToken (statementInfo* const st)
613 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
614 st->tokenIndex = 0;
615 else
616 ++st->tokenIndex;
617 initToken(st->token[st->tokenIndex]);
620 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
622 unsigned int tokenIndex;
623 unsigned int num = (unsigned int) NumTokens;
624 Assert(n < num);
625 tokenIndex = (st->tokenIndex + num - n) % num;
627 return st->token[tokenIndex];
630 static void setToken (statementInfo *const st, const tokenType type)
632 tokenInfo *token;
633 token = activeToken (st);
634 initToken(token);
635 token->type = type;
638 static void retardToken (statementInfo *const st)
640 if (st->tokenIndex == 0)
641 st->tokenIndex = (unsigned int) NumTokens - 1;
642 else
643 --st->tokenIndex;
644 setToken(st, TOKEN_NONE);
647 static tokenInfo *newToken (void)
649 tokenInfo *const token = xMalloc (1, tokenInfo);
650 token->name = vStringNew();
651 initToken(token);
652 return token;
655 static void deleteToken (tokenInfo *const token)
657 if (token != NULL)
659 vStringDelete(token->name);
660 eFree(token);
664 static const char *accessString (const accessType laccess)
666 static const char *const names [] = {
667 "?", "private", "protected", "public", "default"
669 Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
670 Assert ((int) laccess < ACCESS_COUNT);
671 return names[(int) laccess];
674 static const char *implementationString (const impType imp)
676 static const char *const names [] = {
677 "?", "abstract", "virtual", "pure virtual"
679 Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
680 Assert ((int) imp < IMP_COUNT);
681 return names [(int) imp];
685 * Debugging functions
688 #ifdef TM_DEBUG
690 #define boolString(c) ((c) ? "TRUE" : "FALSE")
692 static const char *tokenString (const tokenType type)
694 static const char *const names [] = {
695 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
696 "package", "paren-name", "semicolon", "specifier", "*", "[]"
698 Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
699 Assert ((int) type < TOKEN_COUNT);
700 return names[(int) type];
703 static const char *scopeString (const tagScope scope)
705 static const char *const names [] = {
706 "global", "static", "extern", "friend", "typedef"
708 Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
709 Assert ((int) scope < SCOPE_COUNT);
710 return names[(int) scope];
713 static const char *declString (const declType declaration)
715 static const char *const names [] = {
716 "?", "base", "class", "enum", "event", "signal", "function",
717 "function template", "ignore", "interface", "module", "namespace",
718 "no mangle", "package", "struct", "union",
720 Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
721 Assert ((int) declaration < DECL_COUNT);
722 return names[(int) declaration];
725 static const char *keywordString (const keywordId keyword)
727 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
728 const char *name = "none";
729 size_t i;
730 for (i = 0 ; i < count ; ++i)
732 const keywordDesc *p = &KeywordTable[i];
734 if (p->id == keyword)
736 name = p->name;
737 break;
740 return name;
743 static void UNUSED pt (tokenInfo *const token)
745 if (isType (token, TOKEN_NAME))
746 printf("type: %-12s: %-13s line: %lu\n",
747 tokenString (token->type), vStringValue (token->name),
748 token->lineNumber);
749 else if (isType (token, TOKEN_KEYWORD))
750 printf("type: %-12s: %-13s line: %lu\n",
751 tokenString (token->type), keywordString (token->keyword),
752 token->lineNumber);
753 else
754 printf("type: %-12s line: %lu\n",
755 tokenString (token->type), token->lineNumber);
758 static void UNUSED ps (statementInfo *const st)
760 unsigned int i;
761 printf("scope: %s decl: %s gotName: %s gotParenName: %s\n",
762 scopeString (st->scope), declString (st->declaration),
763 boolString (st->gotName), boolString (st->gotParenName));
764 printf("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
765 printf("access: %s default: %s\n", accessString (st->member.access),
766 accessString (st->member.accessDefault));
767 printf("token : ");
768 pt(activeToken (st));
769 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
771 printf("prev %u : ", i);
772 pt(prevToken (st, i));
774 printf("context: ");
775 pt(st->context);
778 #endif
781 * Statement management
784 static boolean isDataTypeKeyword (const tokenInfo *const token)
786 switch (token->keyword)
788 case KEYWORD_BOOLEAN:
789 case KEYWORD_BYTE:
790 case KEYWORD_CHAR:
791 case KEYWORD_DOUBLE:
792 case KEYWORD_FLOAT:
793 case KEYWORD_INT:
794 case KEYWORD_LONG:
795 case KEYWORD_SHORT:
796 case KEYWORD_VOID:
797 case KEYWORD_WCHAR_T:
798 case KEYWORD_SIZE_T:
799 return TRUE;
800 default:
801 return FALSE;
805 #if 0
806 static boolean isVariableKeyword (const tokenInfo *const token)
808 switch (token->keyword)
810 case KEYWORD_CONST:
811 case KEYWORD_EXTERN:
812 case KEYWORD_REGISTER:
813 case KEYWORD_STATIC:
814 case KEYWORD_VIRTUAL:
815 case KEYWORD_SIGNED:
816 case KEYWORD_UNSIGNED:
817 return TRUE;
818 default:
819 return FALSE;
822 #endif
824 static boolean isContextualKeyword (const tokenInfo *const token)
826 boolean result;
827 switch (token->keyword)
829 case KEYWORD_CLASS:
830 case KEYWORD_ENUM:
831 case KEYWORD_INTERFACE:
832 case KEYWORD_NAMESPACE:
833 case KEYWORD_STRUCT:
834 case KEYWORD_UNION:
836 result = TRUE;
837 break;
840 default:
842 result = FALSE;
843 break;
846 return result;
849 static boolean isContextualStatement (const statementInfo *const st)
851 boolean result = FALSE;
853 if (st != NULL)
855 if (isLanguage (Lang_vala))
857 /* All can be a contextual statment as properties can be of any type */
858 result = TRUE;
860 else
862 switch (st->declaration)
864 case DECL_CLASS:
865 case DECL_ENUM:
866 case DECL_INTERFACE:
867 case DECL_NAMESPACE:
868 case DECL_STRUCT:
869 case DECL_UNION:
871 result = TRUE;
872 break;
875 default:
877 result = FALSE;
878 break;
883 return result;
886 static boolean isMember (const statementInfo *const st)
888 boolean result;
889 if (isType (st->context, TOKEN_NAME))
890 result = TRUE;
891 else
892 result = isContextualStatement (st->parent);
893 return result;
896 static void initMemberInfo (statementInfo *const st)
898 accessType accessDefault = ACCESS_UNDEFINED;
900 if (st->parent != NULL) switch (st->parent->declaration)
902 case DECL_ENUM:
903 case DECL_NAMESPACE:
905 accessDefault = ACCESS_UNDEFINED;
906 break;
908 case DECL_CLASS:
910 if (isLanguage (Lang_java))
911 accessDefault = ACCESS_DEFAULT;
912 else
913 accessDefault = ACCESS_PRIVATE;
914 break;
916 case DECL_INTERFACE:
917 case DECL_STRUCT:
918 case DECL_UNION:
920 accessDefault = ACCESS_PUBLIC;
921 break;
923 default:
924 break;
926 st->member.accessDefault = accessDefault;
927 st->member.access = accessDefault;
930 static void reinitStatement (statementInfo *const st, const boolean partial)
932 unsigned int i;
934 if (! partial)
936 st->scope = SCOPE_GLOBAL;
937 if (isContextualStatement (st->parent))
938 st->declaration = DECL_BASE;
939 else
940 st->declaration = DECL_NONE;
942 st->gotParenName = FALSE;
943 st->implementation = IMP_DEFAULT;
944 st->gotArgs = FALSE;
945 st->gotName = FALSE;
946 st->nSemicolons = 0;
947 st->haveQualifyingName = FALSE;
948 st->argEndPosition = 0;
950 st->tokenIndex = 0;
951 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
953 initToken (st->token [i]);
956 initToken (st->context);
957 initToken (st->blockName);
958 vStringClear (st->parentClasses);
960 /* Init member info. */
961 if (! partial)
962 st->member.access = st->member.accessDefault;
964 /* Init first token */
965 if (!partial)
966 initToken(st->firstToken);
969 static void reinitStatementWithToken (statementInfo *const st,
970 tokenInfo *token, const boolean partial)
972 tokenInfo *const save = newToken ();
973 /* given token can be part of reinit statementInfo */
974 copyToken (save, token);
975 reinitStatement (st, partial);
976 token = activeToken (st);
977 copyToken (token, save);
978 deleteToken (save);
979 ++st->tokenIndex; /* this is quite save becouse current tokenIndex = 0 */
982 static void initStatement (statementInfo *const st, statementInfo *const parent)
984 st->parent = parent;
985 initMemberInfo (st);
986 reinitStatement (st, FALSE);
987 if (parent)
989 const tokenInfo *const src = activeToken (parent);
990 tokenInfo *const dst = activeToken (st);
991 copyToken (dst, src);
992 st->tokenIndex++;
997 * Tag generation functions
999 static cKind cTagKind (const tagType type)
1001 cKind result = CK_UNDEFINED;
1002 switch (type)
1004 case TAG_CLASS: result = CK_CLASS; break;
1005 case TAG_ENUM: result = CK_ENUMERATION; break;
1006 case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
1007 case TAG_FUNCTION: result = CK_FUNCTION; break;
1008 case TAG_MEMBER: result = CK_MEMBER; break;
1009 case TAG_NAMESPACE: result = CK_NAMESPACE; break;
1010 case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
1011 case TAG_STRUCT: result = CK_STRUCT; break;
1012 case TAG_TYPEDEF: result = CK_TYPEDEF; break;
1013 case TAG_UNION: result = CK_UNION; break;
1014 case TAG_VARIABLE: result = CK_VARIABLE; break;
1015 case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
1017 default: Assert ("Bad C tag type" == NULL); break;
1019 return result;
1022 static csharpKind csharpTagKind (const tagType type)
1024 csharpKind result = CSK_UNDEFINED;
1025 switch (type)
1027 case TAG_CLASS: result = CSK_CLASS; break;
1028 case TAG_ENUM: result = CSK_ENUMERATION; break;
1029 case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
1030 case TAG_EVENT: result = CSK_EVENT; break;
1031 case TAG_FIELD: result = CSK_FIELD ; break;
1032 case TAG_INTERFACE: result = CSK_INTERFACE; break;
1033 case TAG_LOCAL: result = CSK_LOCAL; break;
1034 case TAG_METHOD: result = CSK_METHOD; break;
1035 case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
1036 case TAG_PROPERTY: result = CSK_PROPERTY; break;
1037 case TAG_STRUCT: result = CSK_STRUCT; break;
1038 case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
1040 default: Assert ("Bad C# tag type" == NULL); break;
1042 return result;
1045 static dKind dTagKind (const tagType type)
1047 dKind result = DK_UNDEFINED;
1048 switch (type)
1050 case TAG_CLASS: result = DK_CLASS; break;
1051 case TAG_ENUM: result = DK_ENUMERATION; break;
1052 case TAG_ENUMERATOR: result = DK_ENUMERATOR; break;
1053 case TAG_FUNCTION: result = DK_FUNCTION; break;
1054 case TAG_INTERFACE: result = DK_INTERFACE; break;
1055 case TAG_MEMBER: result = DK_MEMBER; break;
1056 case TAG_NAMESPACE: result = DK_NAMESPACE; break;
1057 case TAG_PROTOTYPE: result = DK_PROTOTYPE; break;
1058 case TAG_STRUCT: result = DK_STRUCT; break;
1059 case TAG_TYPEDEF: result = DK_TYPEDEF; break;
1060 case TAG_UNION: result = DK_UNION; break;
1061 case TAG_VARIABLE: result = DK_VARIABLE; break;
1062 case TAG_EXTERN_VAR: result = DK_EXTERN_VARIABLE; break;
1064 default: Assert ("Bad D tag type" == NULL); break;
1066 return result;
1069 static valaKind valaTagKind (const tagType type)
1071 valaKind result = VK_UNDEFINED;
1072 switch (type)
1074 case TAG_CLASS: result = VK_CLASS; break;
1075 case TAG_ENUM: result = VK_ENUMERATION; break;
1076 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
1077 case TAG_SIGNAL: result = VK_SIGNAL; break;
1078 case TAG_FIELD: result = VK_FIELD ; break;
1079 case TAG_INTERFACE: result = VK_INTERFACE; break;
1080 case TAG_LOCAL: result = VK_LOCAL; break;
1081 case TAG_METHOD: result = VK_METHOD; break;
1082 case TAG_NAMESPACE: result = VK_NAMESPACE; break;
1083 case TAG_PROPERTY: result = VK_PROPERTY; break;
1084 case TAG_STRUCT: result = VK_STRUCT; break;
1086 default: Assert ("Bad Vala tag type" == NULL); break;
1088 return result;
1091 static javaKind javaTagKind (const tagType type)
1093 javaKind result = JK_UNDEFINED;
1094 switch (type)
1096 case TAG_CLASS: result = JK_CLASS; break;
1097 case TAG_FIELD: result = JK_FIELD; break;
1098 case TAG_INTERFACE: result = JK_INTERFACE; break;
1099 case TAG_METHOD: result = JK_METHOD; break;
1100 case TAG_PACKAGE: result = JK_PACKAGE; break;
1101 case TAG_ENUM: result = JK_ENUMERATION; break;
1102 case TAG_ENUMERATOR: result = JK_ENUMERATOR; break;
1104 default: Assert ("Bad Java tag type" == NULL); break;
1106 return result;
1109 static const char *tagName (const tagType type)
1111 const char* result;
1112 if (isLanguage (Lang_java))
1113 result = JavaKinds [javaTagKind (type)].name;
1114 else if (isLanguage (Lang_csharp))
1115 result = CsharpKinds [csharpTagKind (type)].name;
1116 else if (isLanguage (Lang_d))
1117 result = DKinds [dTagKind (type)].name;
1118 else if (isLanguage (Lang_vala))
1119 result = ValaKinds [valaTagKind (type)].name;
1120 else
1121 result = CKinds [cTagKind (type)].name;
1122 return result;
1125 static int tagLetter (const tagType type)
1127 int result;
1128 if (isLanguage (Lang_csharp))
1129 result = CsharpKinds [csharpTagKind (type)].letter;
1130 else if (isLanguage (Lang_d))
1131 result = DKinds [dTagKind (type)].letter;
1132 else if (isLanguage (Lang_java))
1133 result = JavaKinds [javaTagKind (type)].letter;
1134 else if (isLanguage (Lang_vala))
1135 result = ValaKinds [valaTagKind (type)].letter;
1136 else
1137 result = CKinds [cTagKind (type)].letter;
1138 return result;
1142 static boolean includeTag (const tagType type, const boolean isFileScope)
1144 boolean result;
1145 if (isFileScope && ! Option.include.fileScope)
1146 result = FALSE;
1147 else if (isLanguage (Lang_java))
1148 result = JavaKinds [javaTagKind (type)].enabled;
1149 else
1150 result = CKinds [cTagKind (type)].enabled;
1151 return result;
1155 static tagType declToTagType (const declType declaration)
1157 tagType type = TAG_UNDEFINED;
1159 switch (declaration)
1161 case DECL_CLASS: type = TAG_CLASS; break;
1162 case DECL_ENUM: type = TAG_ENUM; break;
1163 case DECL_FUNCTION: type = TAG_FUNCTION; break;
1164 case DECL_FUNCTION_TEMPLATE: type = TAG_FUNCTION; break;
1165 case DECL_INTERFACE:type = TAG_INTERFACE; break;
1166 case DECL_NAMESPACE:type = TAG_NAMESPACE; break;
1167 case DECL_STRUCT: type = TAG_STRUCT; break;
1168 case DECL_UNION: type = TAG_UNION; break;
1170 default: Assert ("Unexpected declaration" == NULL); break;
1172 return type;
1175 static const char* accessField (const statementInfo *const st)
1177 const char* result = NULL;
1179 if ((isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite)) &&
1180 st->scope == SCOPE_FRIEND)
1181 result = "friend";
1182 else if (st->member.access != ACCESS_UNDEFINED)
1183 result = accessString (st->member.access);
1184 return result;
1187 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
1188 const statementInfo *const st, vString *const scope)
1190 /* For selected tag types, append an extension flag designating the
1191 * parent object in which the tag is defined.
1193 switch (type)
1195 default: break;
1197 case TAG_NAMESPACE:
1198 /* D nested template block */
1199 if (!isLanguage(Lang_d))
1200 break;
1201 case TAG_CLASS:
1202 case TAG_ENUM:
1203 case TAG_ENUMERATOR:
1204 case TAG_FIELD:
1205 case TAG_FUNCTION:
1206 case TAG_INTERFACE:
1207 case TAG_MEMBER:
1208 case TAG_METHOD:
1209 case TAG_PROTOTYPE:
1210 case TAG_STRUCT:
1211 case TAG_TYPEDEF:
1212 case TAG_UNION:
1214 if (vStringLength (scope) > 0 &&
1215 (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1217 if (isType (st->context, TOKEN_NAME))
1218 tag->extensionFields.scope [0] = tagName (TAG_CLASS);
1219 else
1220 tag->extensionFields.scope [0] =
1221 tagName (declToTagType (parentDecl (st)));
1222 tag->extensionFields.scope [1] = vStringValue (scope);
1224 if ((type == TAG_CLASS || type == TAG_INTERFACE ||
1225 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
1227 tag->extensionFields.inheritance =
1228 vStringValue (st->parentClasses);
1230 if (st->implementation != IMP_DEFAULT &&
1231 (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
1232 isLanguage (Lang_java) || isLanguage (Lang_d) || isLanguage (Lang_ferite)))
1234 tag->extensionFields.implementation =
1235 implementationString (st->implementation);
1237 if (isMember (st))
1239 tag->extensionFields.access = accessField (st);
1241 if ((TRUE == st->gotArgs) && (TRUE == Option.extensionFields.argList) &&
1242 ((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type)))
1244 tag->extensionFields.arglist = getArglistFromFilePos(
1245 tag->filePosition, tag->name);
1247 break;
1251 if ((TAG_FIELD == tag->type) || (TAG_MEMBER == tag->type) ||
1252 (TAG_EXTERN_VAR == tag->type) || (TAG_TYPEDEF == tag->type) ||
1253 (TAG_VARIABLE == tag->type) || (TAG_METHOD == tag->type) ||
1254 (TAG_PROTOTYPE == tag->type) || (TAG_FUNCTION == tag->type))
1256 if (((TOKEN_NAME == st->firstToken->type) || isDataTypeKeyword(st->firstToken))
1257 && (0 != strcmp(vStringValue(st->firstToken->name), tag->name)))
1259 tag->extensionFields.varType = getVarType(st);
1264 static const char *getVarType (const statementInfo *const st)
1266 static vString *vt = NULL;
1267 unsigned int i;
1269 if (! st->gotArgs)
1270 return vStringValue(st->firstToken->name); /* ignore non-functions */
1272 if (vt == NULL)
1273 vt = vStringNew();
1274 else
1275 vStringClear(vt);
1277 for (i = 0; i < st->tokenIndex; i++)
1279 tokenInfo *t = st->token[i];
1281 switch (t->type)
1283 case TOKEN_NAME: /* user typename */
1284 if (strcmp(vStringValue(t->name), vStringValue(st->firstToken->name)) != 0)
1285 continue;
1286 break;
1287 case TOKEN_KEYWORD:
1288 if (t->keyword != KEYWORD_EXTERN && t->keyword != KEYWORD_STATIC) /* uninteresting keywords */
1289 break;
1290 continue;
1291 case TOKEN_STAR: vStringCatS(vt, " *"); continue;
1292 case TOKEN_ARRAY: vStringCatS(vt, "[]"); continue;
1293 default: continue;
1295 if (vStringLength(vt) > 0)
1296 if (isalpha(vStringValue(vt)[vStringLength(vt) - 1]))
1297 vStringPut(vt, ' ');
1298 vStringCat(vt, t->name);
1300 vStringTerminate(vt);
1301 return vStringValue(vt);
1304 static void addContextSeparator (vString *const scope)
1306 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
1307 vStringCatS (scope, "::");
1308 else if (isLanguage (Lang_java) || isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
1309 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1310 vStringCatS (scope, ".");
1313 static void findScopeHierarchy (vString *const string,
1314 const statementInfo *const st)
1316 const char* const anon = "<anonymous>";
1317 boolean nonAnonPresent = FALSE;
1319 vStringClear (string);
1320 if (isType (st->context, TOKEN_NAME))
1322 vStringCopy (string, st->context->name);
1323 nonAnonPresent = TRUE;
1325 if (st->parent != NULL)
1327 vString *temp = vStringNew ();
1328 const statementInfo *s;
1330 for (s = st->parent ; s != NULL ; s = s->parent)
1332 if (isContextualStatement (s) ||
1333 s->declaration == DECL_NAMESPACE)
1335 vStringCopy (temp, string);
1336 vStringClear (string);
1337 if (isType (s->blockName, TOKEN_NAME))
1339 if (isType (s->context, TOKEN_NAME) &&
1340 vStringLength (s->context->name) > 0)
1342 vStringCat (string, s->context->name);
1343 addContextSeparator (string);
1345 vStringCat (string, s->blockName->name);
1346 nonAnonPresent = TRUE;
1348 else
1349 vStringCopyS (string, anon);
1350 if (vStringLength (temp) > 0)
1351 addContextSeparator (string);
1352 vStringCat (string, temp);
1355 vStringDelete (temp);
1357 if (! nonAnonPresent)
1358 vStringClear (string);
1362 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1363 vString *const scope)
1365 if (Option.include.qualifiedTags &&
1366 scope != NULL && vStringLength (scope) > 0)
1368 vString *const scopedName = vStringNew ();
1370 if (type != TAG_ENUMERATOR)
1371 vStringCopy (scopedName, scope);
1372 else
1374 /* remove last component (i.e. enumeration name) from scope */
1375 const char* const sc = vStringValue (scope);
1376 const char* colon = strrchr (sc, ':');
1377 if (colon != NULL)
1379 while (*colon == ':' && colon > sc)
1380 --colon;
1381 vStringNCopy (scopedName, scope, colon + 1 - sc);
1384 if (vStringLength (scopedName) > 0)
1386 addContextSeparator (scopedName);
1387 vStringCatS (scopedName, e->name);
1388 e->name = vStringValue (scopedName);
1389 makeTagEntry (e);
1391 vStringDelete (scopedName);
1395 static void makeTag (const tokenInfo *const token,
1396 const statementInfo *const st,
1397 boolean isFileScope, const tagType type)
1399 #ifdef DEBUG_C
1400 printToken(token);
1401 fprintf(stderr, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
1402 printStatement(st);
1403 #endif
1404 /* Nothing is really of file scope when it appears in a header file.
1406 isFileScope = (boolean) (isFileScope && ! isHeaderFile ());
1408 if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 /* &&
1409 includeTag (type, isFileScope) */)
1411 vString *scope = vStringNew ();
1412 tagEntryInfo e;
1414 /* take only functions which are introduced by "function ..." */
1415 if (type == TAG_FUNCTION && isLanguage (Lang_ferite) &&
1416 strncmp("function", st->firstToken->name->buffer, 8) != 0)
1418 return;
1421 initTagEntry (&e, vStringValue (token->name));
1423 e.lineNumber = token->lineNumber;
1424 e.filePosition = token->filePosition;
1425 e.isFileScope = isFileScope;
1426 e.kindName = tagName (type);
1427 e.kind = tagLetter (type);
1428 e.type = type;
1430 findScopeHierarchy (scope, st);
1431 addOtherFields (&e, type, st, scope);
1433 #ifdef DEBUG_C
1434 printTagEntry(&e);
1435 #endif
1436 makeTagEntry (&e);
1437 if (NULL != TagEntryFunction)
1438 makeExtraTagEntry (type, &e, scope);
1439 vStringDelete (scope);
1440 if (NULL != e.extensionFields.arglist)
1441 free((char *) e.extensionFields.arglist);
1445 static boolean isValidTypeSpecifier (const declType declaration)
1447 boolean result;
1448 switch (declaration)
1450 case DECL_BASE:
1451 case DECL_CLASS:
1452 case DECL_ENUM:
1453 case DECL_STRUCT:
1454 case DECL_UNION:
1455 result = TRUE;
1456 break;
1458 default:
1459 result = FALSE;
1460 break;
1462 return result;
1465 static void qualifyEnumeratorTag (const statementInfo *const st,
1466 const tokenInfo *const nameToken)
1468 if (isType (nameToken, TOKEN_NAME))
1469 makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
1472 static void qualifyFunctionTag (const statementInfo *const st,
1473 const tokenInfo *const nameToken)
1475 if (isType (nameToken, TOKEN_NAME))
1477 const tagType type = (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1478 ? TAG_METHOD : TAG_FUNCTION;
1479 const boolean isFileScope =
1480 (boolean) (st->member.access == ACCESS_PRIVATE ||
1481 (!isMember (st) && st->scope == SCOPE_STATIC));
1483 makeTag (nameToken, st, isFileScope, type);
1487 static void qualifyFunctionDeclTag (const statementInfo *const st,
1488 const tokenInfo *const nameToken)
1490 if (! isType (nameToken, TOKEN_NAME))
1492 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1493 qualifyFunctionTag (st, nameToken);
1494 else if (st->scope == SCOPE_TYPEDEF)
1495 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1496 else if (isValidTypeSpecifier (st->declaration) &&
1497 ! (isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1498 makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
1501 static void qualifyCompoundTag (const statementInfo *const st,
1502 const tokenInfo *const nameToken)
1504 if (isType (nameToken, TOKEN_NAME))
1506 const tagType type = declToTagType (st->declaration);
1508 if (type != TAG_UNDEFINED)
1509 makeTag (nameToken, st, (boolean) (! isLanguage (Lang_java) &&
1510 ! isLanguage (Lang_csharp) &&
1511 ! isLanguage (Lang_vala)), type);
1515 static void qualifyBlockTag (statementInfo *const st,
1516 const tokenInfo *const nameToken)
1518 switch (st->declaration)
1520 case DECL_CLASS:
1521 case DECL_ENUM:
1522 case DECL_INTERFACE:
1523 case DECL_NAMESPACE:
1524 case DECL_STRUCT:
1525 case DECL_UNION:
1526 qualifyCompoundTag (st, nameToken);
1527 break;
1528 default: break;
1532 static void qualifyVariableTag (const statementInfo *const st,
1533 const tokenInfo *const nameToken)
1535 /* We have to watch that we do not interpret a declaration of the
1536 * form "struct tag;" as a variable definition. In such a case, the
1537 * token preceding the name will be a keyword.
1539 if (! isType (nameToken, TOKEN_NAME))
1541 else if (st->declaration == DECL_IGNORE)
1543 else if (st->scope == SCOPE_TYPEDEF)
1544 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1545 else if (st->declaration == DECL_PACKAGE)
1546 makeTag (nameToken, st, FALSE, TAG_PACKAGE);
1547 else if (st->declaration == DECL_MODULE) /* handle modules in D as namespaces */
1548 makeTag (nameToken, st, FALSE, TAG_NAMESPACE);
1549 else if (isValidTypeSpecifier (st->declaration))
1551 if (isMember (st))
1553 if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1554 makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1555 else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1556 makeTag (nameToken, st, TRUE, TAG_MEMBER);
1558 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1560 else
1562 if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1563 makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
1564 else
1565 makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC), TAG_VARIABLE);
1571 * Parsing functions
1574 static int skipToOneOf (const char *const chars)
1576 int c;
1578 c = cppGetc ();
1579 while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1581 return c;
1584 /* Skip to the next non-white character.
1586 static int skipToNonWhite (void)
1588 int c;
1592 c = cppGetc ();
1594 while (isspace (c));
1596 return c;
1599 /* Skips to the next brace in column 1. This is intended for cases where
1600 * preprocessor constructs result in unbalanced braces.
1602 static void skipToFormattedBraceMatch (void)
1604 int c, next;
1606 c = cppGetc ();
1607 next = cppGetc ();
1608 while (c != EOF && (c != '\n' || next != '}'))
1610 c = next;
1611 next = cppGetc ();
1615 /* Skip to the matching character indicated by the pair string. If skipping
1616 * to a matching brace and any brace is found within a different level of a
1617 * #if conditional statement while brace formatting is in effect, we skip to
1618 * the brace matched by its formatting. It is assumed that we have already
1619 * read the character which starts the group (i.e. the first character of
1620 * "pair").
1622 static void skipToMatch (const char *const pair)
1624 const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
1625 const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
1626 const unsigned int initialLevel = getDirectiveNestLevel ();
1627 const int begin = pair [0], end = pair [1];
1628 const unsigned long inputLineNumber = getInputLineNumber ();
1629 int matchLevel = 1;
1630 int c = '\0';
1631 if (isLanguage(Lang_d) && pair[0] == '<')
1632 return; /* ignore e.g. Foo!(x < 2) */
1633 while (matchLevel > 0 && (c = cppGetc ()) != EOF)
1635 if (c == begin)
1637 ++matchLevel;
1638 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1640 skipToFormattedBraceMatch ();
1641 break;
1644 else if (c == end)
1646 --matchLevel;
1647 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1649 skipToFormattedBraceMatch ();
1650 break;
1653 /* early out if matching "<>" and we encounter a ";" or "{" to mitigate
1654 * match problems with C++ generics containing a static expression like
1655 * foo<X<Y> bar;
1656 * normally neither ";" nor "{" could appear inside "<>" anyway. */
1657 else if (isLanguage (Lang_cpp) && begin == '<' &&
1658 (c == ';' || c == '{'))
1660 cppUngetc (c);
1661 break;
1664 if (c == EOF)
1666 verbose ("%s: failed to find match for '%c' at line %lu\n",
1667 getInputFileName (), begin, inputLineNumber);
1668 if (braceMatching)
1669 longjmp (Exception, (int) ExceptionBraceFormattingError);
1670 else
1671 longjmp (Exception, (int) ExceptionFormattingError);
1675 static void skipParens (void)
1677 const int c = skipToNonWhite ();
1679 if (c == '(')
1680 skipToMatch ("()");
1681 else
1682 cppUngetc (c);
1685 static void skipBraces (void)
1687 const int c = skipToNonWhite ();
1689 if (c == '{')
1690 skipToMatch ("{}");
1691 else
1692 cppUngetc (c);
1695 static keywordId analyzeKeyword (const char *const name)
1697 const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1699 /* ignore D @attributes and Java @annotations(...), but show them in function signatures */
1700 if ((isLanguage(Lang_d) || isLanguage(Lang_java)) && id == KEYWORD_NONE && name[0] == '@')
1702 skipParens(); /* if annotation has parameters, skip them */
1703 return KEYWORD_CONST;
1705 return id;
1708 static void analyzeIdentifier (tokenInfo *const token)
1710 char *const name = vStringValue (token->name);
1711 const char *replacement = NULL;
1712 boolean parensToo = FALSE;
1714 if (isLanguage (Lang_java) ||
1715 ! isIgnoreToken (name, &parensToo, &replacement))
1717 if (replacement != NULL)
1718 token->keyword = analyzeKeyword (replacement);
1719 else
1720 token->keyword = analyzeKeyword (vStringValue (token->name));
1722 if (token->keyword == KEYWORD_NONE)
1723 token->type = TOKEN_NAME;
1724 else
1725 token->type = TOKEN_KEYWORD;
1727 else
1729 initToken (token);
1730 if (parensToo)
1732 int c = skipToNonWhite ();
1734 if (c == '(')
1735 skipToMatch ("()");
1740 static void readIdentifier (tokenInfo *const token, const int firstChar)
1742 vString *const name = token->name;
1743 int c = firstChar;
1745 initToken (token);
1747 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1748 * the ~ and the class name. */
1749 if (isLanguage (Lang_cpp) && firstChar == '~')
1751 vStringPut (name, c);
1752 c = skipToNonWhite ();
1757 vStringPut (name, c);
1758 c = cppGetc ();
1759 } while (isident (c) || (isLanguage (Lang_vala) && '.' == c));
1760 vStringTerminate (name);
1761 cppUngetc (c); /* unget non-identifier character */
1763 /* Vala supports '?' at end of a type (with or without whitespace before) for nullable types */
1764 if (isLanguage (Lang_vala))
1766 c = skipToNonWhite ();
1767 if ('?' == c)
1768 vStringPut (name, c);
1769 else
1770 cppUngetc (c);
1773 analyzeIdentifier (token);
1776 static void readPackageName (tokenInfo *const token, const int firstChar)
1778 vString *const name = token->name;
1779 int c = firstChar;
1781 initToken (token);
1783 while (isident (c) || c == '.')
1785 vStringPut (name, c);
1786 c = cppGetc ();
1788 vStringTerminate (name);
1789 cppUngetc (c); /* unget non-package character */
1792 static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1794 st->declaration = declaration;
1796 if (declaration == DECL_NAMESPACE && !(isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1798 /* In C++ a namespace is specified one level at a time. */
1799 return;
1801 else
1803 /* In C#, a namespace can also be specified like a Java package name. */
1804 tokenInfo *const token = activeToken (st);
1805 Assert (isType (token, TOKEN_KEYWORD));
1806 readPackageName (token, skipToNonWhite ());
1807 token->type = TOKEN_NAME;
1808 st->gotName = TRUE;
1809 st->haveQualifyingName = TRUE;
1813 static void readPackage (statementInfo *const st)
1815 tokenInfo *const token = activeToken (st);
1816 Assert (isType (token, TOKEN_KEYWORD));
1817 readPackageName (token, skipToNonWhite ());
1818 token->type = TOKEN_NAME;
1819 if (isLanguage (Lang_d))
1820 st->declaration = DECL_MODULE;
1821 else
1822 st->declaration = DECL_PACKAGE;
1823 st->gotName = TRUE;
1824 st->haveQualifyingName = TRUE;
1827 static void processName (statementInfo *const st)
1829 Assert (isType (activeToken (st), TOKEN_NAME));
1830 if (st->gotName && st->declaration == DECL_NONE)
1831 st->declaration = DECL_BASE;
1832 st->gotName = TRUE;
1833 st->haveQualifyingName = TRUE;
1836 static void readOperator (statementInfo *const st)
1838 const char *const acceptable = "+-*/%^&|~!=<>,[]";
1839 const tokenInfo* const prev = prevToken (st,1);
1840 tokenInfo *const token = activeToken (st);
1841 vString *const name = token->name;
1842 int c = skipToNonWhite ();
1844 /* When we arrive here, we have the keyword "operator" in 'name'.
1846 if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1847 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1848 ; /* ignore "operator" keyword if preceded by these keywords */
1849 else if (c == '(')
1851 /* Verify whether this is a valid function call (i.e. "()") operator.
1853 if (cppGetc () == ')')
1855 vStringPut (name, ' '); /* always separate operator from keyword */
1856 c = skipToNonWhite ();
1857 if (c == '(')
1858 vStringCatS (name, "()");
1860 else
1862 skipToMatch ("()");
1863 c = cppGetc ();
1866 else if (isident1 (c))
1868 /* Handle "new" and "delete" operators, and conversion functions
1869 * (per 13.3.1.1.2 [2] of the C++ spec).
1871 boolean whiteSpace = TRUE; /* default causes insertion of space */
1874 if (isspace (c))
1875 whiteSpace = TRUE;
1876 else
1878 if (whiteSpace)
1880 vStringPut (name, ' ');
1881 whiteSpace = FALSE;
1883 vStringPut (name, c);
1885 c = cppGetc ();
1886 } while (! isOneOf (c, "(;") && c != EOF);
1887 vStringTerminate (name);
1889 else if (isOneOf (c, acceptable))
1891 vStringPut (name, ' '); /* always separate operator from keyword */
1894 vStringPut (name, c);
1895 c = cppGetc ();
1896 } while (isOneOf (c, acceptable));
1897 vStringTerminate (name);
1900 cppUngetc (c);
1902 token->type = TOKEN_NAME;
1903 token->keyword = KEYWORD_NONE;
1904 processName (st);
1907 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1909 dest->type = src->type;
1910 dest->keyword = src->keyword;
1911 dest->filePosition = src->filePosition;
1912 dest->lineNumber = src->lineNumber;
1913 vStringCopy (dest->name, src->name);
1916 static void setAccess (statementInfo *const st, const accessType laccess)
1918 if (isMember (st))
1920 if (isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite))
1922 int c = skipToNonWhite ();
1924 if (c == ':')
1925 reinitStatementWithToken (st, prevToken (st, 1), FALSE);
1926 else
1927 cppUngetc (c);
1929 st->member.accessDefault = laccess;
1931 st->member.access = laccess;
1935 static void discardTypeList (tokenInfo *const token)
1937 int c = skipToNonWhite ();
1938 while (isident1 (c))
1940 readIdentifier (token, c);
1941 c = skipToNonWhite ();
1942 if (c == '.' || c == ',')
1943 c = skipToNonWhite ();
1945 cppUngetc (c);
1948 static void addParentClass (statementInfo *const st, tokenInfo *const token)
1950 if (vStringLength (token->name) > 0 &&
1951 vStringLength (st->parentClasses) > 0)
1953 vStringPut (st->parentClasses, ',');
1955 vStringCat (st->parentClasses, token->name);
1958 static void readParents (statementInfo *const st, const int qualifier)
1960 tokenInfo *const token = newToken ();
1961 tokenInfo *const parent = newToken ();
1962 int c;
1966 c = skipToNonWhite ();
1967 if (isident1 (c))
1969 readIdentifier (token, c);
1970 if (isType (token, TOKEN_NAME))
1971 vStringCat (parent->name, token->name);
1972 else
1974 addParentClass (st, parent);
1975 initToken (parent);
1978 else if (c == qualifier)
1979 vStringPut (parent->name, c);
1980 else if (c == '<')
1981 skipToMatch ("<>");
1982 else if (isType (token, TOKEN_NAME))
1984 addParentClass (st, parent);
1985 initToken (parent);
1987 } while (c != '{' && c != EOF);
1988 cppUngetc (c);
1989 deleteToken (parent);
1990 deleteToken (token);
1993 static void checkIsClassEnum (statementInfo *const st, const declType decl)
1995 if (! isLanguage (Lang_cpp) || st->declaration != DECL_ENUM)
1996 st->declaration = decl;
1999 static void processToken (tokenInfo *const token, statementInfo *const st)
2001 switch (token->keyword) /* is it a reserved word? */
2003 default: break;
2005 case KEYWORD_NONE: processName (st); break;
2006 case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
2007 case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
2008 case KEYWORD_CATCH: skipParens (); skipBraces (); break;
2009 case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
2010 case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break;
2011 case KEYWORD_CONST: st->declaration = DECL_BASE; break;
2012 case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
2013 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
2014 case KEYWORD_EXTENDS: readParents (st, '.');
2015 setToken (st, TOKEN_NONE); break;
2016 case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
2017 case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
2018 case KEYWORD_IMPLEMENTS:readParents (st, '.');
2019 setToken (st, TOKEN_NONE); break;
2020 case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
2021 case KEYWORD_INT: st->declaration = DECL_BASE; break;
2022 case KEYWORD_BOOLEAN: st->declaration = DECL_BASE; break;
2023 case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
2024 case KEYWORD_SIZE_T: st->declaration = DECL_BASE; break;
2025 case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
2026 case KEYWORD_LONG: st->declaration = DECL_BASE; break;
2027 case KEYWORD_OPERATOR: readOperator (st); break;
2028 case KEYWORD_MODULE: readPackage (st); break;
2029 case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
2030 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
2031 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
2032 case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
2033 case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
2034 case KEYWORD_STRUCT: checkIsClassEnum (st, DECL_STRUCT); break;
2035 case KEYWORD_STATIC_ASSERT: skipParens (); break;
2036 case KEYWORD_THROWS: discardTypeList (token); break;
2037 case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
2038 case KEYWORD_UNION: st->declaration = DECL_UNION; break;
2039 case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
2040 case KEYWORD_USING: st->declaration = DECL_IGNORE; break;
2041 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
2042 case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
2043 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
2045 case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
2046 case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
2047 case KEYWORD_EVENT:
2049 if (isLanguage (Lang_csharp))
2050 st->declaration = DECL_EVENT;
2051 break;
2053 case KEYWORD_SIGNAL:
2055 if (isLanguage (Lang_vala))
2056 st->declaration = DECL_SIGNAL;
2057 break;
2059 case KEYWORD_EXTERN:
2061 if (! isLanguage (Lang_csharp) || !st->gotName)
2063 /*reinitStatement (st, FALSE);*/
2064 st->scope = SCOPE_EXTERN;
2065 st->declaration = DECL_BASE;
2067 break;
2069 case KEYWORD_STATIC:
2071 if (! isLanguage (Lang_java) && ! isLanguage (Lang_csharp) && ! isLanguage (Lang_vala))
2073 /*reinitStatement (st, FALSE);*/
2074 st->scope = SCOPE_STATIC;
2075 st->declaration = DECL_BASE;
2077 break;
2079 case KEYWORD_IF:
2080 if (isLanguage (Lang_d))
2081 { /* static if (is(typeof(__traits(getMember, a, name)) == function)) */
2082 int c = skipToNonWhite ();
2083 if (c == '(')
2084 skipToMatch ("()");
2086 break;
2091 * Parenthesis handling functions
2094 static void restartStatement (statementInfo *const st)
2096 tokenInfo *const save = newToken ();
2097 tokenInfo *token = activeToken (st);
2099 copyToken (save, token);
2100 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
2101 reinitStatement (st, FALSE);
2102 token = activeToken (st);
2103 copyToken (token, save);
2104 deleteToken (save);
2105 processToken (token, st);
2108 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
2110 * mem-initializer-list:
2111 * mem-initializer, mem-initializer-list
2113 * mem-initializer:
2114 * [::] [nested-name-spec] class-name (...)
2115 * identifier
2117 static void skipMemIntializerList (tokenInfo *const token)
2119 int c;
2123 c = skipToNonWhite ();
2124 while (isident1 (c) || c == ':')
2126 if (c != ':')
2127 readIdentifier (token, c);
2128 c = skipToNonWhite ();
2130 if (c == '<')
2132 skipToMatch ("<>");
2133 c = skipToNonWhite ();
2135 if (c == '(')
2137 skipToMatch ("()");
2138 c = skipToNonWhite ();
2140 } while (c == ',');
2141 cppUngetc (c);
2144 static void skipMacro (statementInfo *const st)
2146 tokenInfo *const prev2 = prevToken (st, 2);
2148 if (isType (prev2, TOKEN_NAME))
2149 retardToken (st);
2150 skipToMatch ("()");
2153 static boolean isDPostArgumentToken(tokenInfo *const token)
2155 switch (token->keyword)
2157 /* Note: some other keywords e.g. immutable are parsed as
2158 * KEYWORD_CONST - see initializeDParser */
2159 case KEYWORD_CONST:
2160 /* template constraint */
2161 case KEYWORD_IF:
2162 /* contracts */
2163 case KEYWORD_IN:
2164 case KEYWORD_OUT:
2165 case KEYWORD_BODY:
2166 return TRUE;
2167 default:
2168 break;
2170 /* @attributes */
2171 if (vStringValue(token->name)[0] == '@')
2172 return TRUE;
2173 return FALSE;
2176 /* Skips over characters following the parameter list. This will be either
2177 * non-ANSI style function declarations or C++ stuff. Our choices:
2179 * C (K&R):
2180 * int func ();
2181 * int func (one, two) int one; float two; {...}
2182 * C (ANSI):
2183 * int func (int one, float two);
2184 * int func (int one, float two) {...}
2185 * C++:
2186 * int foo (...) [const|volatile] [throw (...)];
2187 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2188 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2189 * catch (...) {...}
2191 static boolean skipPostArgumentStuff (statementInfo *const st,
2192 parenInfo *const info)
2194 tokenInfo *const token = activeToken (st);
2195 unsigned int parameters = info->parameterCount;
2196 unsigned int elementCount = 0;
2197 boolean restart = FALSE;
2198 boolean end = FALSE;
2199 int c = skipToNonWhite ();
2203 switch (c)
2205 case ')': break;
2206 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
2207 case '[': skipToMatch ("[]"); break;
2208 case '=': cppUngetc (c); end = TRUE; break;
2209 case '{': cppUngetc (c); end = TRUE; break;
2210 case '}': cppUngetc (c); end = TRUE; break;
2212 case '(':
2214 if (elementCount > 0)
2215 ++elementCount;
2216 skipToMatch ("()");
2217 break;
2220 case ';':
2222 if (parameters == 0 || elementCount < 2)
2224 cppUngetc (c);
2225 end = TRUE;
2227 else if (--parameters == 0)
2228 end = TRUE;
2229 break;
2232 default:
2234 if (isident1 (c))
2236 readIdentifier (token, c);
2237 if (isLanguage(Lang_d) && isDPostArgumentToken(token))
2238 token->keyword = KEYWORD_CONST;
2240 switch (token->keyword)
2242 case KEYWORD_ATTRIBUTE: skipParens (); break;
2243 case KEYWORD_THROW: skipParens (); break;
2244 case KEYWORD_CONST: break;
2245 case KEYWORD_TRY: break;
2246 case KEYWORD_VOLATILE: break;
2248 case KEYWORD_CATCH: case KEYWORD_CLASS:
2249 case KEYWORD_EXPLICIT: case KEYWORD_EXTERN:
2250 case KEYWORD_FRIEND: case KEYWORD_INLINE:
2251 case KEYWORD_MUTABLE: case KEYWORD_NAMESPACE:
2252 case KEYWORD_NEW: case KEYWORD_OPERATOR:
2253 case KEYWORD_OVERLOAD: case KEYWORD_PRIVATE:
2254 case KEYWORD_PROTECTED: case KEYWORD_PUBLIC:
2255 case KEYWORD_STATIC: case KEYWORD_TEMPLATE:
2256 case KEYWORD_TYPEDEF: case KEYWORD_TYPENAME:
2257 case KEYWORD_USING: case KEYWORD_VIRTUAL:
2258 /* Never allowed within parameter declarations.
2260 restart = TRUE;
2261 end = TRUE;
2262 break;
2264 default:
2265 if (isType (token, TOKEN_NONE))
2267 else if (info->isKnrParamList && info->parameterCount > 0)
2268 ++elementCount;
2269 else
2271 /* If we encounter any other identifier immediately
2272 * following an empty parameter list, this is almost
2273 * certainly one of those Microsoft macro "thingies"
2274 * that the automatic source code generation sticks
2275 * in. Terminate the current statement.
2277 restart = TRUE;
2278 end = TRUE;
2280 break;
2285 if (! end)
2287 c = skipToNonWhite ();
2288 if (c == EOF)
2289 end = TRUE;
2291 } while (! end);
2293 if (restart)
2294 restartStatement (st);
2295 else
2296 setToken (st, TOKEN_NONE);
2297 return (boolean) (c != EOF);
2300 static void skipJavaThrows (statementInfo *const st)
2302 tokenInfo *const token = activeToken (st);
2303 int c = skipToNonWhite ();
2305 if (isident1 (c))
2307 readIdentifier (token, c);
2308 if (token->keyword == KEYWORD_THROWS)
2312 c = skipToNonWhite ();
2313 if (isident1 (c))
2315 readIdentifier (token, c);
2316 c = skipToNonWhite ();
2318 } while (c == '.' || c == ',');
2321 cppUngetc (c);
2322 setToken (st, TOKEN_NONE);
2325 static void skipValaPostParens (statementInfo *const st)
2327 tokenInfo *const token = activeToken (st);
2328 int c = skipToNonWhite ();
2330 while (isident1 (c))
2332 readIdentifier (token, c);
2333 if (token->keyword == KEYWORD_ATTRIBUTE)
2335 /* parse contracts */
2336 skipParens ();
2337 c = skipToNonWhite ();
2339 else if (token->keyword == KEYWORD_THROWS)
2343 c = skipToNonWhite ();
2344 if (isident1 (c))
2346 readIdentifier (token, c);
2347 c = skipToNonWhite ();
2349 } while (c == '.' || c == ',');
2351 else
2352 break;
2354 cppUngetc (c);
2355 setToken (st, TOKEN_NONE);
2358 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2360 const unsigned long inputLineNumber = getInputLineNumber ();
2361 int c = skipToNonWhite ();
2363 cppUngetc (c);
2364 if (isOneOf (c, "{;,="))
2366 else if (isLanguage (Lang_java))
2367 skipJavaThrows (st);
2368 else if (isLanguage (Lang_vala))
2369 skipValaPostParens(st);
2370 else
2372 if (! skipPostArgumentStuff (st, info))
2374 verbose (
2375 "%s: confusing argument declarations beginning at line %lu\n",
2376 getInputFileName (), inputLineNumber);
2377 longjmp (Exception, (int) ExceptionFormattingError);
2382 static int parseParens (statementInfo *const st, parenInfo *const info)
2384 tokenInfo *const token = activeToken (st);
2385 unsigned int identifierCount = 0;
2386 unsigned int depth = 1;
2387 boolean firstChar = TRUE;
2388 int nextChar = '\0';
2390 info->parameterCount = 1;
2393 int c = skipToNonWhite ();
2395 switch (c)
2397 case '&':
2398 case '*':
2400 /* DEBUG_PRINT("parseParens, po++\n"); */
2401 info->isKnrParamList = FALSE;
2402 if (identifierCount == 0)
2403 info->isParamList = FALSE;
2404 initToken (token);
2405 break;
2407 case ':':
2409 info->isKnrParamList = FALSE;
2410 break;
2412 case '.':
2414 info->isNameCandidate = FALSE;
2415 info->isKnrParamList = FALSE;
2416 break;
2418 case ',':
2420 info->isNameCandidate = FALSE;
2421 if (info->isKnrParamList)
2423 ++info->parameterCount;
2424 identifierCount = 0;
2426 break;
2428 case '=':
2430 info->isKnrParamList = FALSE;
2431 info->isNameCandidate = FALSE;
2432 if (firstChar)
2434 info->isParamList = FALSE;
2435 skipMacro (st);
2436 depth = 0;
2438 break;
2440 case '[':
2442 info->isKnrParamList = FALSE;
2443 skipToMatch ("[]");
2444 break;
2446 case '<':
2448 info->isKnrParamList = FALSE;
2449 skipToMatch ("<>");
2450 break;
2452 case ')':
2454 if (firstChar)
2455 info->parameterCount = 0;
2456 --depth;
2457 break;
2459 case '(':
2461 info->isKnrParamList = FALSE;
2462 if (firstChar)
2464 info->isNameCandidate = FALSE;
2465 cppUngetc (c);
2466 skipMacro (st);
2467 depth = 0;
2469 else if (isType (token, TOKEN_PAREN_NAME))
2471 c = skipToNonWhite ();
2472 if (c == '*') /* check for function pointer */
2474 skipToMatch ("()");
2475 c = skipToNonWhite ();
2476 if (c == '(')
2477 skipToMatch ("()");
2479 else
2481 cppUngetc (c);
2482 cppUngetc ('(');
2483 info->nestedArgs = TRUE;
2486 else
2487 ++depth;
2488 break;
2491 default:
2493 if (isident1 (c))
2495 if (++identifierCount > 1)
2496 info->isKnrParamList = FALSE;
2497 readIdentifier (token, c);
2498 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2499 token->type = TOKEN_PAREN_NAME;
2500 else if (isType (token, TOKEN_KEYWORD))
2502 info->isKnrParamList = FALSE;
2503 info->isNameCandidate = FALSE;
2506 else if (isLanguage(Lang_d) && c == '!')
2507 { /* D template instantiation */
2508 info->isNameCandidate = FALSE;
2509 info->isKnrParamList = FALSE;
2511 else
2513 info->isParamList = FALSE;
2514 info->isKnrParamList = FALSE;
2515 info->isNameCandidate = FALSE;
2516 info->invalidContents = TRUE;
2518 break;
2521 firstChar = FALSE;
2522 } while (! info->nestedArgs && depth > 0 &&
2523 (info->isKnrParamList || info->isNameCandidate));
2525 if (! info->nestedArgs) while (depth > 0)
2527 skipToMatch ("()");
2528 --depth;
2530 if (st->argEndPosition == 0)
2531 st->argEndPosition = mio_tell (File.mio);
2533 if (! info->isNameCandidate)
2534 initToken (token);
2536 return nextChar;
2539 static void initParenInfo (parenInfo *const info)
2541 info->isParamList = TRUE;
2542 info->isKnrParamList = TRUE;
2543 info->isNameCandidate = TRUE;
2544 info->invalidContents = FALSE;
2545 info->nestedArgs = FALSE;
2546 info->parameterCount = 0;
2549 static void analyzeParens (statementInfo *const st)
2551 tokenInfo *const prev = prevToken (st, 1);
2553 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2555 tokenInfo *const token = activeToken (st);
2556 parenInfo info;
2557 int c;
2559 initParenInfo (&info);
2560 parseParens (st, &info);
2562 c = skipToNonWhite ();
2564 cppUngetc (c);
2565 if (info.invalidContents)
2567 reinitStatement (st, FALSE);
2569 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2570 ! st->gotParenName &&
2571 (! info.isParamList || ! st->haveQualifyingName ||
2572 c == '(' ||
2573 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2574 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2576 token->type = TOKEN_NAME;
2577 processName (st);
2578 st->gotParenName = TRUE;
2579 if (isLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME))
2581 st->declaration = DECL_FUNCTION_TEMPLATE;
2582 copyToken (st->blockName, prev);
2585 else if (! st->gotArgs && info.isParamList)
2587 st->gotArgs = TRUE;
2588 setToken (st, TOKEN_ARGS);
2589 advanceToken (st);
2590 analyzePostParens (st, &info);
2592 else
2594 setToken (st, TOKEN_NONE);
2600 * Token parsing functions
2603 static void addContext (statementInfo *const st, const tokenInfo* const token)
2605 if (isType (token, TOKEN_NAME))
2607 if (vStringLength (st->context->name) > 0)
2609 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
2610 vStringCatS (st->context->name, "::");
2611 else if (isLanguage (Lang_java) ||
2612 isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
2613 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
2614 vStringCatS (st->context->name, ".");
2616 vStringCat (st->context->name, token->name);
2617 st->context->type = TOKEN_NAME;
2621 static boolean inheritingDeclaration (declType decl)
2623 return (boolean) (decl == DECL_CLASS ||
2624 decl == DECL_STRUCT ||
2625 decl == DECL_INTERFACE);
2628 static void processColon (statementInfo *const st)
2630 int c = skipToNonWhite ();
2631 const boolean doubleColon = (boolean) (c == ':');
2633 if (doubleColon)
2635 setToken (st, TOKEN_DOUBLE_COLON);
2636 st->haveQualifyingName = FALSE;
2638 else
2640 cppUngetc (c);
2641 if (((isLanguage (Lang_cpp) &&
2642 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT)) ||
2643 isLanguage (Lang_csharp) || isLanguage (Lang_d) || isLanguage (Lang_vala)) &&
2644 inheritingDeclaration (st->declaration))
2646 readParents (st, ':');
2648 else if ((isLanguage (Lang_cpp) || isLanguage (Lang_csharp)) &&
2649 st->declaration == DECL_ENUM)
2651 /* skip enum's base type */
2652 c = skipToOneOf ("{;");
2653 if (c == '{')
2654 setToken (st, TOKEN_BRACE_OPEN);
2655 else if (c == ';')
2656 setToken (st, TOKEN_SEMICOLON);
2658 else if (parentDecl (st) == DECL_STRUCT || parentDecl (st) == DECL_CLASS)
2660 c = skipToOneOf (",;");
2661 if (c == ',')
2662 setToken (st, TOKEN_COMMA);
2663 else if (c == ';')
2664 setToken (st, TOKEN_SEMICOLON);
2666 else
2668 const tokenInfo *const prev = prevToken (st, 1);
2669 const tokenInfo *const prev2 = prevToken (st, 2);
2670 if (prev->keyword == KEYWORD_DEFAULT ||
2671 prev2->keyword == KEYWORD_CASE ||
2672 st->parent != NULL)
2674 reinitStatement (st, FALSE);
2680 /* Skips over any initializing value which may follow an '=' character in a
2681 * variable definition.
2683 static int skipInitializer (statementInfo *const st)
2685 boolean done = FALSE;
2686 int c;
2688 while (! done)
2690 c = skipToNonWhite ();
2692 if (c == EOF)
2693 longjmp (Exception, (int) ExceptionFormattingError);
2694 else switch (c)
2696 case ',':
2697 case ';': done = TRUE; break;
2699 case '0':
2700 if (st->implementation == IMP_VIRTUAL)
2701 st->implementation = IMP_PURE_VIRTUAL;
2702 break;
2704 case '[': skipToMatch ("[]"); break;
2705 case '(': skipToMatch ("()"); break;
2706 case '{': skipToMatch ("{}"); break;
2708 case '}':
2709 if (insideEnumBody (st))
2710 done = TRUE;
2711 else if (! isBraceFormat ())
2713 verbose ("%s: unexpected closing brace at line %lu\n",
2714 getInputFileName (), getInputLineNumber ());
2715 longjmp (Exception, (int) ExceptionBraceFormattingError);
2717 break;
2719 default: break;
2722 return c;
2725 static void processInitializer (statementInfo *const st)
2727 const boolean inEnumBody = insideEnumBody (st);
2728 const int c = skipInitializer (st);
2730 if (c == ';')
2731 setToken (st, TOKEN_SEMICOLON);
2732 else if (c == ',')
2733 setToken (st, TOKEN_COMMA);
2734 else if (c == '}' && inEnumBody)
2736 cppUngetc (c);
2737 setToken (st, TOKEN_COMMA);
2739 if (st->scope == SCOPE_EXTERN)
2740 st->scope = SCOPE_GLOBAL;
2743 static void parseIdentifier (statementInfo *const st, const int c)
2745 tokenInfo *const token = activeToken (st);
2747 readIdentifier (token, c);
2748 if (! isType (token, TOKEN_NONE))
2749 processToken (token, st);
2752 static void parseGeneralToken (statementInfo *const st, const int c)
2754 const tokenInfo *const prev = prevToken (st, 1);
2756 if (isident1(c))
2758 parseIdentifier (st, c);
2759 if (isType (st->context, TOKEN_NAME) &&
2760 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2762 initToken (st->context);
2765 else if (isExternCDecl (st, c))
2767 st->declaration = DECL_NOMANGLE;
2768 st->scope = SCOPE_GLOBAL;
2772 /* Reads characters from the pre-processor and assembles tokens, setting
2773 * the current statement state.
2775 static void nextToken (statementInfo *const st)
2777 int c;
2778 tokenInfo *token = activeToken (st);
2781 c = skipToNonWhite();
2782 switch (c)
2784 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2785 case '(': analyzeParens (st); token = activeToken (st); break;
2786 case '*': setToken (st, TOKEN_STAR); break;
2787 case ',': setToken (st, TOKEN_COMMA); break;
2788 case ':': processColon (st); break;
2789 case ';': setToken (st, TOKEN_SEMICOLON); break;
2790 case '<': skipToMatch ("<>"); break;
2791 case '=': processInitializer (st); break;
2792 case '[':
2793 /* Hack for Vala: [..] can be a function attribute.
2794 * Seems not to have bad side effects, but have to test it more. */
2795 if (!isLanguage (Lang_vala))
2796 setToken (st, TOKEN_ARRAY);
2797 skipToMatch ("[]");
2798 break;
2799 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2800 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2801 default: parseGeneralToken (st, c); break;
2803 } while (isType (token, TOKEN_NONE));
2805 if (isType (token, TOKEN_SEMICOLON) && st->parent)
2806 st->parent->nSemicolons ++;
2808 /* We want to know about non-keyword variable types */
2809 if (TOKEN_NONE == st->firstToken->type)
2811 if ((TOKEN_NAME == token->type) || isDataTypeKeyword(token))
2812 copyToken(st->firstToken, token);
2817 * Scanning support functions
2819 static unsigned int contextual_fake_count = 0;
2820 static statementInfo *CurrentStatement = NULL;
2822 static statementInfo *newStatement (statementInfo *const parent)
2824 statementInfo *const st = xMalloc (1, statementInfo);
2825 unsigned int i;
2827 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2828 st->token [i] = newToken ();
2830 st->context = newToken ();
2831 st->blockName = newToken ();
2832 st->parentClasses = vStringNew ();
2833 st->firstToken = newToken();
2835 initStatement (st, parent);
2836 CurrentStatement = st;
2838 return st;
2841 static void deleteStatement (void)
2843 statementInfo *const st = CurrentStatement;
2844 statementInfo *const parent = st->parent;
2845 unsigned int i;
2847 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2849 deleteToken(st->token[i]); st->token[i] = NULL;
2851 deleteToken(st->blockName); st->blockName = NULL;
2852 deleteToken(st->context); st->context = NULL;
2853 vStringDelete(st->parentClasses); st->parentClasses = NULL;
2854 deleteToken(st->firstToken);
2855 eFree (st);
2856 CurrentStatement = parent;
2859 static void deleteAllStatements (void)
2861 while (CurrentStatement != NULL)
2862 deleteStatement ();
2865 static boolean isStatementEnd (const statementInfo *const st)
2867 const tokenInfo *const token = activeToken (st);
2868 boolean isEnd;
2870 if (isType (token, TOKEN_SEMICOLON))
2871 isEnd = TRUE;
2872 else if (isType (token, TOKEN_BRACE_CLOSE))
2873 /* Java, D, C#, Vala do not require semicolons to end a block. Neither do
2874 * C++ namespaces. All other blocks require a semicolon to terminate them.
2876 isEnd = (boolean) (isLanguage (Lang_java) || isLanguage (Lang_d) ||
2877 isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
2878 ! isContextualStatement (st));
2879 else
2880 isEnd = FALSE;
2882 return isEnd;
2885 static void checkStatementEnd (statementInfo *const st)
2887 const tokenInfo *const token = activeToken (st);
2888 boolean comma = isType (token, TOKEN_COMMA);
2890 if (comma || isStatementEnd (st))
2892 reinitStatementWithToken (st, activeToken (st), comma);
2894 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2895 cppEndStatement ();
2897 else
2899 cppBeginStatement ();
2900 advanceToken (st);
2904 static void nest (statementInfo *const st, const unsigned int nestLevel)
2906 switch (st->declaration)
2908 case DECL_CLASS:
2909 case DECL_ENUM:
2910 case DECL_INTERFACE:
2911 case DECL_NAMESPACE:
2912 case DECL_NOMANGLE:
2913 case DECL_STRUCT:
2914 case DECL_UNION:
2915 createTags (nestLevel, st);
2916 break;
2917 default:
2918 skipToMatch ("{}");
2919 break;
2921 advanceToken (st);
2922 setToken (st, TOKEN_BRACE_CLOSE);
2925 static void tagCheck (statementInfo *const st)
2927 const tokenInfo *const token = activeToken (st);
2928 const tokenInfo *const prev = prevToken (st, 1);
2929 const tokenInfo *const prev2 = prevToken (st, 2);
2931 switch (token->type)
2933 case TOKEN_NAME:
2935 if (insideEnumBody (st) &&
2936 /* Java enumerations can contain members after a semicolon */
2937 (! isLanguage(Lang_java) || st->parent->nSemicolons < 1))
2938 qualifyEnumeratorTag (st, token);
2939 break;
2941 #if 0
2942 case TOKEN_PACKAGE:
2944 if (st->haveQualifyingName)
2945 makeTag (token, st, FALSE, TAG_PACKAGE);
2946 break;
2948 #endif
2949 case TOKEN_BRACE_OPEN:
2951 if (isType (prev, TOKEN_ARGS))
2953 if (st->declaration == DECL_FUNCTION_TEMPLATE)
2954 qualifyFunctionTag (st, st->blockName);
2955 else if (st->haveQualifyingName)
2957 if (isType (prev2, TOKEN_NAME))
2958 copyToken (st->blockName, prev2);
2959 /* D structure templates */
2960 if (isLanguage (Lang_d) &&
2961 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT ||
2962 st->declaration == DECL_INTERFACE || st->declaration == DECL_NAMESPACE))
2963 qualifyBlockTag (st, prev2);
2964 else
2966 st->declaration = DECL_FUNCTION;
2967 qualifyFunctionTag (st, prev2);
2971 else if (isContextualStatement (st))
2973 tokenInfo *name_token = (tokenInfo *)prev;
2974 boolean free_name_token = FALSE;
2976 if (isType (name_token, TOKEN_NAME))
2978 if (!isLanguage (Lang_vala))
2979 copyToken (st->blockName, name_token);
2980 else
2982 switch (st->declaration)
2984 case DECL_CLASS:
2985 case DECL_ENUM:
2986 case DECL_INTERFACE:
2987 case DECL_NAMESPACE:
2988 case DECL_STRUCT:
2989 copyToken (st->blockName, name_token);
2990 break;
2992 /* anything else can be a property */
2993 default:
2994 /* makeTag (prev, st, FALSE, TAG_PROPERTY); */
2995 /* FIXME: temporary hack to get properties shown */
2996 makeTag (prev, st, FALSE, TAG_FIELD);
2997 break;
3001 /* C++ 11 allows class <name> final { ... } */
3002 else if (isLanguage (Lang_cpp) && isType (prev, TOKEN_KEYWORD) &&
3003 prev->keyword == KEYWORD_FINAL && isType(prev2, TOKEN_NAME))
3005 name_token = (tokenInfo *)prev2;
3006 copyToken (st->blockName, name_token);
3008 else if (isLanguage (Lang_csharp))
3009 makeTag (prev, st, FALSE, TAG_PROPERTY);
3010 else
3012 tokenInfo *contextual_token = (tokenInfo *)prev;
3013 if(isContextualKeyword (contextual_token))
3015 char buffer[64];
3017 name_token = newToken ();
3018 free_name_token = TRUE;
3019 copyToken (name_token, contextual_token);
3021 sprintf(buffer, "anon_%s_%d", name_token->name->buffer, contextual_fake_count++);
3022 vStringClear(name_token->name);
3023 vStringCatS(name_token->name, buffer);
3025 name_token->type = TOKEN_NAME;
3026 name_token->keyword = KEYWORD_NONE;
3028 advanceToken (st);
3029 contextual_token = activeToken (st);
3030 copyToken (contextual_token, token);
3031 copyToken ((tokenInfo *const)token, name_token);
3032 copyToken (st->blockName, name_token);
3033 copyToken (st->firstToken, name_token);
3036 qualifyBlockTag (st, name_token);
3037 if (free_name_token)
3038 deleteToken (name_token);
3040 break;
3042 case TOKEN_ARRAY:
3043 case TOKEN_SEMICOLON:
3044 case TOKEN_COMMA:
3046 if (insideEnumBody (st) &&
3047 /* Java enumerations can contain members after a semicolon */
3048 (! isLanguage (Lang_java) || st->parent->nSemicolons < 2))
3050 else if (isType (prev, TOKEN_NAME))
3052 if (isContextualKeyword (prev2))
3053 makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
3054 else
3055 qualifyVariableTag (st, prev);
3057 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
3059 qualifyFunctionDeclTag (st, prev2);
3061 break;
3063 default:
3064 break;
3068 /* Parses the current file and decides whether to write out and tags that
3069 * are discovered.
3071 static void createTags (const unsigned int nestLevel,
3072 statementInfo *const parent)
3074 statementInfo *const st = newStatement (parent);
3076 DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
3077 while (TRUE)
3079 tokenInfo *token;
3081 nextToken (st);
3083 token = activeToken (st);
3085 if (isType (token, TOKEN_BRACE_CLOSE))
3087 if (nestLevel > 0)
3088 break;
3089 else
3091 verbose ("%s: unexpected closing brace at line %lu\n",
3092 getInputFileName (), getInputLineNumber ());
3093 longjmp (Exception, (int) ExceptionBraceFormattingError);
3096 else if (isType (token, TOKEN_DOUBLE_COLON))
3098 addContext (st, prevToken (st, 1));
3099 advanceToken (st);
3101 else
3103 tagCheck (st);/* this can add new token */
3104 if (isType (activeToken (st), TOKEN_BRACE_OPEN))
3105 nest (st, nestLevel + 1);
3106 checkStatementEnd (st);
3109 deleteStatement ();
3110 DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
3113 static boolean findCTags (const unsigned int passCount)
3115 exception_t exception;
3116 boolean retry;
3118 contextual_fake_count = 0;
3120 Assert (passCount < 3);
3121 cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
3123 exception = (exception_t) setjmp (Exception);
3124 retry = FALSE;
3126 if (exception == ExceptionNone)
3128 createTags (0, NULL);
3130 else
3132 deleteAllStatements ();
3133 if (exception == ExceptionBraceFormattingError && passCount == 1)
3135 retry = TRUE;
3136 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3137 getInputFileName ());
3140 cppTerminate ();
3141 return retry;
3144 static void buildKeywordHash (const langType language, unsigned int idx)
3146 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
3147 size_t i;
3148 for (i = 0 ; i < count ; ++i)
3150 const keywordDesc* const p = &KeywordTable [i];
3151 if (p->isValid [idx])
3152 addKeyword (p->name, language, (int) p->id);
3156 static void initializeCParser (const langType language)
3158 Lang_c = language;
3159 buildKeywordHash (language, 0);
3162 static void initializeCppParser (const langType language)
3164 Lang_cpp = language;
3165 buildKeywordHash (language, 1);
3168 static void initializeJavaParser (const langType language)
3170 Lang_java = language;
3171 buildKeywordHash (language, 3);
3174 static void initializeDParser (const langType language)
3176 /* treat these like const - some are for parsing like const(Type), some are just
3177 * function attributes */
3178 const char *const_aliases[] = {"immutable", "nothrow", "pure", "shared", NULL};
3179 const char **s;
3181 Lang_d = language;
3182 buildKeywordHash (language, 6);
3184 for (s = const_aliases; *s != NULL; s++)
3186 addKeyword (*s, language, KEYWORD_CONST);
3188 /* other keyword aliases */
3189 addKeyword ("alias", language, KEYWORD_TYPEDEF);
3190 /* skip 'static assert(...)' like 'static if (...)' */
3191 addKeyword ("assert", language, KEYWORD_IF);
3192 addKeyword ("unittest", language, KEYWORD_BODY); /* ignore */
3193 addKeyword ("version", language, KEYWORD_NAMESPACE); /* parse block */
3196 static void initializeGLSLParser (const langType language)
3198 Lang_glsl = language;
3199 buildKeywordHash (language, 0); /* C keywords */
3202 static void initializeFeriteParser (const langType language)
3204 Lang_ferite = language;
3205 buildKeywordHash (language, 1); /* C++ keywords */
3208 static void initializeCsharpParser (const langType language)
3210 Lang_csharp = language;
3211 buildKeywordHash (language, 2);
3214 static void initializeValaParser (const langType language)
3216 Lang_vala = language;
3217 buildKeywordHash (language, 5);
3219 /* keyword aliases */
3220 addKeyword ("ensures", language, KEYWORD_ATTRIBUTE); /* ignore */
3221 addKeyword ("errordomain", language, KEYWORD_ENUM); /* looks like enum */
3222 addKeyword ("requires", language, KEYWORD_ATTRIBUTE); /* ignore */
3225 extern parserDefinition* CParser (void)
3227 static const char *const extensions [] = { "c", "pc", "sc", NULL };
3228 parserDefinition* def = parserNew ("C");
3229 def->kinds = CKinds;
3230 def->kindCount = KIND_COUNT (CKinds);
3231 def->extensions = extensions;
3232 def->parser2 = findCTags;
3233 def->initialize = initializeCParser;
3234 return def;
3237 extern parserDefinition* CppParser (void)
3239 static const char *const extensions [] = {
3240 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3241 "i",
3242 #ifndef CASE_INSENSITIVE_FILENAMES
3243 "C", "H",
3244 #endif
3245 NULL
3247 parserDefinition* def = parserNew ("C++");
3248 def->kinds = CKinds;
3249 def->kindCount = KIND_COUNT (CKinds);
3250 def->extensions = extensions;
3251 def->parser2 = findCTags;
3252 def->initialize = initializeCppParser;
3253 return def;
3256 extern parserDefinition* JavaParser (void)
3258 static const char *const extensions [] = { "java", NULL };
3259 parserDefinition* def = parserNew ("Java");
3260 def->kinds = JavaKinds;
3261 def->kindCount = KIND_COUNT (JavaKinds);
3262 def->extensions = extensions;
3263 def->parser2 = findCTags;
3264 def->initialize = initializeJavaParser;
3265 return def;
3268 extern parserDefinition* DParser (void)
3270 static const char *const extensions [] = { "d", "di", NULL };
3271 parserDefinition* def = parserNew ("D");
3272 def->kinds = DKinds;
3273 def->kindCount = KIND_COUNT (DKinds);
3274 def->extensions = extensions;
3275 def->parser2 = findCTags;
3276 def->initialize = initializeDParser;
3277 return def;
3280 extern parserDefinition* GLSLParser (void)
3282 static const char *const extensions [] = { "glsl", "frag", "vert", NULL };
3283 parserDefinition* def = parserNew ("GLSL");
3284 def->kinds = CKinds;
3285 def->kindCount = KIND_COUNT (CKinds);
3286 def->extensions = extensions;
3287 def->parser2 = findCTags;
3288 def->initialize = initializeGLSLParser;
3289 return def;
3292 extern parserDefinition* FeriteParser (void)
3294 static const char *const extensions [] = { "fe", NULL };
3295 parserDefinition* def = parserNew ("Ferite");
3296 def->kinds = CKinds;
3297 def->kindCount = KIND_COUNT (CKinds);
3298 def->extensions = extensions;
3299 def->parser2 = findCTags;
3300 def->initialize = initializeFeriteParser;
3301 return def;
3304 extern parserDefinition* CsharpParser (void)
3306 static const char *const extensions [] = { "cs", NULL };
3307 parserDefinition* def = parserNew ("C#");
3308 def->kinds = CsharpKinds;
3309 def->kindCount = KIND_COUNT (CsharpKinds);
3310 def->extensions = extensions;
3311 def->parser2 = findCTags;
3312 def->initialize = initializeCsharpParser;
3313 return def;
3316 extern parserDefinition* ValaParser (void)
3318 static const char *const extensions [] = { "vala", NULL };
3319 parserDefinition* def = parserNew ("Vala");
3320 def->kinds = ValaKinds;
3321 def->kindCount = KIND_COUNT (ValaKinds);
3322 def->extensions = extensions;
3323 def->parser2 = findCTags;
3324 def->initialize = initializeValaParser;
3325 return def;
3327 /* vi:set tabstop=8 shiftwidth=4: */