Make parser includes closer to uctags and sync parser license header
[geany-mirror.git] / ctags / parsers / c.c
blobd6392941b20ab0c30fd4df05bfa23ee7540f3228
1 /*
2 * Copyright (c) 1996-2003, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains functions for parsing and scanning C, C++, C#, D and Java
8 * source files.
9 */
12 * INCLUDE FILES
14 #include "general.h" /* must always come first */
16 #include <string.h>
17 #include <setjmp.h>
19 #include "debug.h"
20 #include "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"
28 #include "routines.h"
29 #include "xtag.h"
32 * MACROS
35 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
36 #define parentDecl(st) ((st)->parent == NULL ? \
37 DECL_NONE : (st)->parent->declaration)
38 #define isType(token,t) (boolean) ((token)->type == (t))
39 #define insideEnumBody(st) (boolean) ((st)->parent == NULL ? FALSE : \
40 ((st)->parent->declaration == DECL_ENUM))
41 #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
42 ! (st)->haveQualifyingName && \
43 (st)->scope == SCOPE_EXTERN)
45 #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
48 * DATA DECLARATIONS
51 enum { NumTokens = 12 };
53 typedef enum eException
55 ExceptionNone, ExceptionEOF, ExceptionFormattingError,
56 ExceptionBraceFormattingError
57 } exception_t;
59 /* Used to specify type of keyword.
61 typedef enum eKeywordId
63 KEYWORD_NONE = -1,
64 KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT, KEYWORD_ALIAS,
65 KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
66 KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT, KEYWORD_BODY,
67 KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
68 KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
69 KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
70 KEYWORD_DOUBLE,
71 KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
72 KEYWORD_EXTENDS, KEYWORD_EVENT,
73 KEYWORD_FINAL, KEYWORD_FINALLY, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FRIEND, KEYWORD_FUNCTION,
74 KEYWORD_GET, KEYWORD_GOTO,
75 KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_IN, KEYWORD_INLINE, KEYWORD_INT,
76 KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
77 KEYWORD_INTERNAL,
78 KEYWORD_LOCAL, KEYWORD_LONG,
79 KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
80 KEYWORD_MODULE, KEYWORD_MUTABLE,
81 KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE, KEYWORD_NOEXCEPT,
82 KEYWORD_OPERATOR, KEYWORD_OUT, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
83 KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE,
84 KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
85 KEYWORD_REF, KEYWORD_REGISTER, KEYWORD_RETURN,
86 KEYWORD_SHADOW, KEYWORD_STATE,
87 KEYWORD_SET, KEYWORD_SHORT, KEYWORD_SIGNAL, KEYWORD_SIGNED, KEYWORD_SIZE_T, KEYWORD_STATIC,
88 KEYWORD_STATIC_ASSERT, KEYWORD_STRING,
89 KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
90 KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
91 KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
92 KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
93 KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
94 KEYWORD_USING,
95 KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
96 KEYWORD_WCHAR_T, KEYWORD_WEAK, KEYWORD_WHILE
97 } keywordId;
99 /* Used to determine whether keyword is valid for the current language and
100 * what its ID is.
102 typedef struct sKeywordDesc
104 const char *name;
105 keywordId id;
106 short isValid [7]; /* indicates languages for which kw is valid */
107 } keywordDesc;
109 /* Used for reporting the type of object parsed by nextToken ().
111 typedef enum eTokenType
113 TOKEN_NONE, /* none */
114 TOKEN_ARGS, /* a parenthetical pair and its contents */
115 TOKEN_BRACE_CLOSE,
116 TOKEN_BRACE_OPEN,
117 TOKEN_COMMA, /* the comma character */
118 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
119 TOKEN_KEYWORD,
120 TOKEN_NAME, /* an unknown name */
121 TOKEN_PACKAGE, /* a Java package name */
122 TOKEN_PAREN_NAME, /* a single name in parentheses */
123 TOKEN_SEMICOLON, /* the semicolon character */
124 TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
125 TOKEN_STAR, /* pointer detection */
126 TOKEN_ARRAY, /* array detection */
127 TOKEN_COUNT
128 } tokenType;
130 /* This describes the scoping of the current statement.
132 typedef enum eTagScope
134 SCOPE_GLOBAL, /* no storage class specified */
135 SCOPE_STATIC, /* static storage class */
136 SCOPE_EXTERN, /* external storage class */
137 SCOPE_FRIEND, /* declares access only */
138 SCOPE_TYPEDEF, /* scoping depends upon context */
139 SCOPE_COUNT
140 } tagScope;
142 typedef enum eDeclaration
144 DECL_NONE,
145 DECL_BASE, /* base type (default) */
146 DECL_CLASS,
147 DECL_ENUM,
148 DECL_EVENT,
149 DECL_SIGNAL,
150 DECL_FUNCTION,
151 DECL_FUNCTION_TEMPLATE,
152 DECL_IGNORE, /* non-taggable "declaration" */
153 DECL_INTERFACE,
154 DECL_MODULE,
155 DECL_NAMESPACE,
156 DECL_NOMANGLE, /* C++ name demangling block */
157 DECL_PACKAGE,
158 DECL_STRUCT,
159 DECL_UNION,
160 DECL_COUNT
161 } declType;
163 typedef enum eVisibilityType
165 ACCESS_UNDEFINED,
166 ACCESS_PRIVATE,
167 ACCESS_PROTECTED,
168 ACCESS_PUBLIC,
169 ACCESS_DEFAULT, /* Java-specific */
170 ACCESS_COUNT
171 } accessType;
173 /* Information about the parent class of a member (if any).
175 typedef struct sMemberInfo
177 accessType access; /* access of current statement */
178 accessType accessDefault; /* access default for current statement */
179 } memberInfo;
181 typedef struct sTokenInfo
183 tokenType type;
184 keywordId keyword;
185 vString* name; /* the name of the token */
186 unsigned long lineNumber; /* line number of tag */
187 MIOPos filePosition; /* file position of line containing name */
188 } tokenInfo;
190 typedef enum eImplementation
192 IMP_DEFAULT,
193 IMP_ABSTRACT,
194 IMP_VIRTUAL,
195 IMP_PURE_VIRTUAL,
196 IMP_COUNT
197 } impType;
199 /* Describes the statement currently undergoing analysis.
201 typedef struct sStatementInfo
203 tagScope scope;
204 declType declaration; /* specifier associated with TOKEN_SPEC */
205 boolean gotName; /* was a name parsed yet? */
206 boolean haveQualifyingName; /* do we have a name we are considering? */
207 boolean gotParenName; /* was a name inside parentheses parsed yet? */
208 boolean gotArgs; /* was a list of parameters parsed yet? */
209 unsigned int nSemicolons; /* how many semicolons did we see in that statement */
210 impType implementation; /* abstract or concrete implementation? */
211 unsigned int tokenIndex; /* currently active token */
212 tokenInfo* token [((int) NumTokens)];
213 tokenInfo* context; /* accumulated scope of current statement */
214 tokenInfo* blockName; /* name of current block */
215 memberInfo member; /* information regarding parent class/struct */
216 vString* parentClasses; /* parent classes */
217 struct sStatementInfo *parent; /* statement we are nested within */
218 long argEndPosition; /* Position where argument list ended */
219 tokenInfo* firstToken; /* First token in the statement */
220 } statementInfo;
222 /* Describes the type of tag being generated.
224 typedef enum eTagType
226 TAG_UNDEFINED,
227 TAG_CLASS, /* class name */
228 TAG_ENUM, /* enumeration name */
229 TAG_ENUMERATOR, /* enumerator (enumeration value) */
230 TAG_FIELD, /* field (Java) */
231 TAG_FUNCTION, /* function definition */
232 TAG_INTERFACE, /* interface declaration */
233 TAG_MEMBER, /* structure, class or interface member */
234 TAG_METHOD, /* method declaration */
235 TAG_NAMESPACE, /* namespace name */
236 TAG_PACKAGE, /* package name */
237 TAG_PROTOTYPE, /* function prototype or declaration */
238 TAG_STRUCT, /* structure name */
239 TAG_TYPEDEF, /* typedef name */
240 TAG_UNION, /* union name */
241 TAG_VARIABLE, /* variable definition */
242 TAG_EXTERN_VAR, /* external variable declaration */
243 TAG_MACRO, /* #define s */
244 TAG_EVENT, /* event */
245 TAG_SIGNAL, /* signal */
246 TAG_LOCAL, /* local variable definition */
247 TAG_PROPERTY, /* property name */
248 TAG_COUNT /* must be last */
249 } tagType;
251 typedef struct sParenInfo
253 boolean isParamList;
254 boolean isKnrParamList;
255 boolean isNameCandidate;
256 boolean invalidContents;
257 boolean nestedArgs;
258 unsigned int parameterCount;
259 } parenInfo;
262 * DATA DEFINITIONS
265 static jmp_buf Exception;
267 static langType Lang_c;
268 static langType Lang_cpp;
269 static langType Lang_csharp;
270 static langType Lang_java;
271 static langType Lang_d;
272 static langType Lang_glsl;
273 static langType Lang_ferite;
274 static langType Lang_vala;
276 /* Used to index into the CKinds table. */
277 typedef enum
279 CK_UNDEFINED = -1,
280 CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
281 CK_ENUMERATION, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
282 CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
283 CK_EXTERN_VARIABLE
284 } cKind;
286 static kindOption CKinds [] = {
287 { TRUE, 'c', "class", "classes"},
288 { TRUE, 'd', "macro", "macro definitions"},
289 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
290 { TRUE, 'f', "function", "function definitions"},
291 { TRUE, 'g', "enum", "enumeration names"},
292 { TRUE, 'm', "member", "class, struct, and union members"},
293 { TRUE, 'n', "namespace", "namespaces"},
294 { FALSE, 'p', "prototype", "function prototypes"},
295 { TRUE, 's', "struct", "structure names"},
296 { TRUE, 't', "typedef", "typedefs"},
297 { TRUE, 'u', "union", "union names"},
298 { TRUE, 'v', "variable", "variable definitions"},
299 { FALSE, 'x', "externvar", "external variable declarations"},
302 /* Used to index into the DKinds table. */
303 typedef enum
305 DK_UNDEFINED = -1,
306 DK_CLASS, DK_ENUMERATOR, DK_FUNCTION,
307 DK_ENUMERATION, DK_INTERFACE, DK_MEMBER, DK_NAMESPACE, DK_PROTOTYPE,
308 DK_STRUCT, DK_TYPEDEF, DK_UNION, DK_VARIABLE,
309 DK_EXTERN_VARIABLE
310 } dKind;
312 static kindOption DKinds [] = {
313 { TRUE, 'c', "class", "classes"},
314 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
315 { TRUE, 'f', "function", "function definitions"},
316 { TRUE, 'g', "enum", "enumeration names"},
317 { TRUE, 'i', "interface", "interfaces"},
318 { TRUE, 'm', "member", "class, struct, and union members"},
319 { TRUE, 'n', "namespace", "namespaces"},
320 { FALSE, 'p', "prototype", "function prototypes"},
321 { TRUE, 's', "struct", "structure names"},
322 { TRUE, 't', "typedef", "typedefs"},
323 { TRUE, 'u', "union", "union names"},
324 { TRUE, 'v', "variable", "variable definitions"},
325 { FALSE, 'x', "externvar", "external variable declarations"},
328 /* Used to index into the JavaKinds table. */
329 typedef enum
331 JK_UNDEFINED = -1,
332 JK_CLASS, JK_FIELD, JK_INTERFACE, JK_METHOD,
333 JK_PACKAGE, JK_ENUMERATOR, JK_ENUMERATION
334 } javaKind;
336 static kindOption JavaKinds [] = {
337 { TRUE, 'c', "class", "classes"},
338 { TRUE, 'f', "field", "fields"},
339 { TRUE, 'i', "interface", "interfaces"},
340 { TRUE, 'm', "method", "methods"},
341 { TRUE, 'p', "package", "packages"},
342 { TRUE, 'e', "enumConstant", "enum constants"},
343 { TRUE, 'g', "enum", "enum types"},
346 typedef enum
348 CSK_UNDEFINED = -1,
349 CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
350 CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
351 CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
352 } csharpKind;
354 static kindOption CsharpKinds [] = {
355 { TRUE, 'c', "class", "classes"},
356 { TRUE, 'd', "macro", "macro definitions"},
357 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
358 { TRUE, 'E', "event", "events"},
359 { TRUE, 'f', "field", "fields"},
360 { TRUE, 'g', "enum", "enumeration names"},
361 { TRUE, 'i', "interface", "interfaces"},
362 { FALSE, 'l', "local", "local variables"},
363 { TRUE, 'm', "method", "methods"},
364 { TRUE, 'n', "namespace", "namespaces"},
365 { TRUE, 'p', "property", "properties"},
366 { TRUE, 's', "struct", "structure names"},
367 { TRUE, 't', "typedef", "typedefs"},
370 typedef enum {
371 VK_UNDEFINED = -1,
372 VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FIELD,
373 VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_METHOD,
374 VK_NAMESPACE, VK_PROPERTY, VK_SIGNAL, VK_STRUCT
375 } valaKind;
377 static kindOption ValaKinds [] = {
378 { TRUE, 'c', "class", "classes"},
379 { TRUE, 'd', "macro", "macro definitions"},
380 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
381 { TRUE, 'f', "field", "fields"},
382 { TRUE, 'g', "enum", "enumeration names"},
383 { TRUE, 'i', "interface", "interfaces"},
384 { FALSE, 'l', "local", "local variables"},
385 { TRUE, 'm', "method", "methods"},
386 { TRUE, 'n', "namespace", "namespaces"},
387 { TRUE, 'p', "property", "properties"},
388 { TRUE, 'S', "signal", "signals"},
389 { TRUE, 's', "struct", "structure names"},
392 /* Note: some keyword aliases are added in initializeDParser, initializeValaParser */
393 static const keywordDesc KeywordTable [] = {
394 /* C++ */
395 /* ANSI C | C# Java */
396 /* | | | | Vera */
397 /* | | | | | Vala */
398 /* | | | | | | D */
399 /* keyword keyword ID | | | | | | | */
400 { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0, 0, 1 } },
401 { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0, 1, 1 } },
402 { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
403 { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
404 { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1, 0, 0 } },
405 { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1, 0, 0 } },
406 { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1, 0, 0 } },
407 { "body", KEYWORD_BODY, { 0, 0, 0, 0, 0, 0, 1 } },
408 { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0, 0, 0 } },
409 { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0, 0, 1 } },
410 { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0, 1, 1 } },
411 { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0, 1, 1 } },
412 { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0, 1, 1 } },
413 { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1, 1, 1 } },
414 { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0, 1, 1 } },
415 { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1, 0, 0 } },
416 { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1, 0, 0 } },
417 { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1, 0, 0 } },
418 { "do", KEYWORD_DO, { 1, 1, 1, 1, 0, 1, 1 } },
419 { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0, 1, 1 } },
420 { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0, 1, 1 } },
421 { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0, 1, 1 } },
422 { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0, 1, 1 } },
423 { "else", KEYWORD_ELSE, { 1, 1, 0, 1, 0, 1, 1 } },
424 { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1, 1, 1 } },
425 { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1, 0, 0 } },
426 { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0, 0, 1 } },
427 { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1, 0, 0 } },
428 { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1, 1, 0 } },
429 { "extern", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
430 { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0, 0, 1 } },
431 { "finally", KEYWORD_FINALLY, { 0, 0, 0, 0, 0, 1, 1 } },
432 { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0, 1, 1 } },
433 { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0, 1, 1 } },
434 { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0, 0, 0 } },
435 { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1, 0, 1 } },
436 { "get", KEYWORD_GET, { 0, 0, 0, 0, 0, 1, 0 } },
437 { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0, 1, 1 } },
438 { "if", KEYWORD_IF, { 1, 1, 1, 1, 0, 1, 1 } },
439 { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0, 0, 0 } },
440 { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0, 0, 1 } },
441 { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0, 1, 0 } },
442 { "in", KEYWORD_IN, { 0, 0, 0, 0, 0, 0, 1 } },
443 { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1, 0, 0 } },
444 { "inout", KEYWORD_CONST, { 0, 0, 0, 0, 0, 0, 1 } }, /* treat like const */
445 { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1, 0, 0 } },
446 { "int", KEYWORD_INT, { 1, 1, 1, 1, 0, 1, 1 } },
447 { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1, 0, 0 } },
448 { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1, 1, 1 } },
449 { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0, 0, 0 } },
450 { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1, 0, 0 } },
451 { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0, 1, 1 } },
452 { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
453 { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
454 { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
455 { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
456 { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0, 0, 0 } },
457 { "module", KEYWORD_MODULE, { 0, 0, 0, 0, 0, 0, 1 } },
458 { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0, 1, 0 } },
459 { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0, 0, 0 } },
460 { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0, 1, 1 } },
461 { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1, 0, 0 } },
462 { "noexcept", KEYWORD_NOEXCEPT, { 0, 1, 0, 0, 0, 0, 0 } },
463 { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0, 0, 0 } },
464 { "out", KEYWORD_OUT, { 0, 0, 0, 0, 0, 1, 1 } },
465 { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1, 0, 0 } },
466 { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0, 0, 0 } },
467 { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0, 1, 1 } },
468 { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0, 0, 1 } },
469 { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1, 0, 0 } },
470 { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1, 0, 0 } },
471 { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0, 1, 1 } },
472 { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1, 0, 0 } },
473 { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1, 1, 1 } },
474 { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1, 1, 1 } },
475 { "ref", KEYWORD_REF, { 0, 0, 0, 0, 0, 1, 1 } },
476 { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0, 0, 0 } },
477 { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0, 1, 1 } },
478 { "set", KEYWORD_SET, { 0, 0, 0, 0, 0, 1, 0 } },
479 { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1, 0, 0 } },
480 { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0, 1, 1 } },
481 { "signal", KEYWORD_SIGNAL, { 0, 0, 0, 0, 0, 1, 0 } },
482 { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0, 0, 0 } },
483 { "size_t", KEYWORD_SIZE_T, { 0, 0, 0, 0, 0, 1, 0 } },
484 { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
485 { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1, 1, 1 } },
486 { "static_assert", KEYWORD_STATIC_ASSERT, { 0, 1, 0, 0, 0, 0, 0 } },
487 { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1, 1, 0 } },
488 { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0, 1, 1 } },
489 { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0, 1, 1 } },
490 { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0, 0, 1 } },
491 { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1, 0, 0 } },
492 { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0, 0, 0 } },
493 { "template", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
494 { "this", KEYWORD_THIS, { 0, 0, 1, 1, 0, 1, 0 } }, /* 0 to allow D ctor tags */
495 { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0, 1, 1 } },
496 { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0, 1, 0 } },
497 { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
498 { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1, 0, 0 } },
499 { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0, 0, 0 } },
500 { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0, 1, 1 } },
501 { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1, 0, 1 } },
502 { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0, 0, 0 } },
503 { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0, 1, 1 } },
504 { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0, 1, 1 } },
505 { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0, 0, 1 } },
506 { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0, 0, 1 } },
507 { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0, 1, 1 } },
508 { "using", KEYWORD_USING, { 0, 1, 1, 0, 0, 1, 0 } },
509 { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1, 1, 0 } },
510 { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1, 1, 1 } },
511 { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0, 0, 1 } },
512 { "wchar_t", KEYWORD_WCHAR_T, { 0, 1, 1, 0, 0, 0, 0 } },
513 { "weak", KEYWORD_WEAK, { 0, 0, 0, 0, 0, 1, 0 } },
514 { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0, 1, 1 } }
519 * FUNCTION PROTOTYPES
521 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
522 static void copyToken (tokenInfo *const dest, const tokenInfo *const src);
523 static const char *getVarType (const statementInfo *const st,
524 const tokenInfo *const token);
527 * FUNCTION DEFINITIONS
530 /* Debugging functions added by Biswa */
531 #if defined(DEBUG_C) && DEBUG_C
532 static char *tokenTypeName[] = {
533 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
534 "package", "paren-name", "';'", "spec", "*", "[]", "count"
537 static char *tagScopeNames[] = {
538 "global", "static", "extern", "friend", "typedef", "count"};
540 static char *declTypeNames[] = {
541 "none", "base", "class", "enum", "function", "ignore", "interface",
542 "namespace", "nomangle", "package", "struct", "union", "count"};
544 static char *impTypeNames[] = {
545 "default", "abstract", "virtual", "pure-virtual", "count"};
547 void printToken(const tokenInfo *const token)
549 fprintf(stderr, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName[token->type],
550 token->keyword, vStringValue(token->name));
553 void printTagEntry(const tagEntryInfo *tag)
555 fprintf(stderr, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag->name,
556 tag->kindName, tag->extensionFields.implementation, tag->extensionFields.scope[1],
557 tag->extensionFields.varType);
560 void printStatement(const statementInfo *const statement)
562 int i;
563 statementInfo *st = (statementInfo *) statement;
564 while (NULL != st)
566 fprintf(stderr, "Statement Info:\n------------------------\n");
567 fprintf(stderr, "scope: %s, decl: %s, impl: %s\n", tagScopeNames[st->scope],
568 declTypeNames[st->declaration], impTypeNames[st->implementation]);
569 for (i=0; i < NumTokens; ++i)
571 fprintf(stderr, "Token %d %s: ", i, (i == st->tokenIndex)?"(current)":"");
572 printToken(st->token[i]);
574 fprintf(stderr, "Context: ");
575 printToken(st->context);
576 fprintf(stderr, "Block: ");
577 printToken(st->blockName);
578 fprintf(stderr, "Parent classes: %s\n", vStringValue(st->parentClasses));
579 fprintf(stderr, "First token: ");
580 printToken(st->firstToken);
581 if (NULL != st->parent)
582 fprintf(stderr, "Printing Parent:\n");
583 st = st->parent;
585 fprintf(stderr, "-----------------------------------------------\n");
587 #endif
589 extern boolean includingDefineTags (void)
591 if (isLanguage(Lang_c) ||
592 isLanguage(Lang_cpp) ||
593 isLanguage(Lang_csharp) ||
594 isLanguage(Lang_ferite) ||
595 isLanguage(Lang_glsl) ||
596 isLanguage(Lang_vala))
597 return CKinds [CK_DEFINE].enabled;
599 return FALSE;
603 * Token management
606 static void initToken (tokenInfo* const token)
608 token->type = TOKEN_NONE;
609 token->keyword = KEYWORD_NONE;
610 token->lineNumber = getSourceLineNumber();
611 token->filePosition = getInputFilePosition();
612 vStringClear(token->name);
615 static void advanceToken (statementInfo* const st)
617 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
618 st->tokenIndex = 0;
619 else
620 ++st->tokenIndex;
621 initToken(st->token[st->tokenIndex]);
624 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
626 unsigned int tokenIndex;
627 unsigned int num = (unsigned int) NumTokens;
628 Assert(n < num);
629 tokenIndex = (st->tokenIndex + num - n) % num;
631 return st->token[tokenIndex];
634 static void setToken (statementInfo *const st, const tokenType type)
636 tokenInfo *token;
637 token = activeToken (st);
638 initToken(token);
639 token->type = type;
642 static void retardToken (statementInfo *const st)
644 if (st->tokenIndex == 0)
645 st->tokenIndex = (unsigned int) NumTokens - 1;
646 else
647 --st->tokenIndex;
648 setToken(st, TOKEN_NONE);
651 static tokenInfo *newToken (void)
653 tokenInfo *const token = xMalloc (1, tokenInfo);
654 token->name = vStringNew();
655 initToken(token);
656 return token;
659 static void deleteToken (tokenInfo *const token)
661 if (token != NULL)
663 vStringDelete(token->name);
664 eFree(token);
668 static const char *accessString (const accessType laccess)
670 static const char *const names [] = {
671 "?", "private", "protected", "public", "default"
673 Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
674 Assert ((int) laccess < ACCESS_COUNT);
675 return names[(int) laccess];
678 static const char *implementationString (const impType imp)
680 static const char *const names [] = {
681 "?", "abstract", "virtual", "pure virtual"
683 Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
684 Assert ((int) imp < IMP_COUNT);
685 return names [(int) imp];
689 * Debugging functions
692 #ifdef TM_DEBUG
694 #define boolString(c) ((c) ? "TRUE" : "FALSE")
696 static const char *tokenString (const tokenType type)
698 static const char *const names [] = {
699 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
700 "package", "paren-name", "semicolon", "specifier", "*", "[]"
702 Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
703 Assert ((int) type < TOKEN_COUNT);
704 return names[(int) type];
707 static const char *scopeString (const tagScope scope)
709 static const char *const names [] = {
710 "global", "static", "extern", "friend", "typedef"
712 Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
713 Assert ((int) scope < SCOPE_COUNT);
714 return names[(int) scope];
717 static const char *declString (const declType declaration)
719 static const char *const names [] = {
720 "?", "base", "class", "enum", "event", "signal", "function",
721 "function template", "ignore", "interface", "module", "namespace",
722 "no mangle", "package", "struct", "union",
724 Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
725 Assert ((int) declaration < DECL_COUNT);
726 return names[(int) declaration];
729 static const char *keywordString (const keywordId keyword)
731 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
732 const char *name = "none";
733 size_t i;
734 for (i = 0 ; i < count ; ++i)
736 const keywordDesc *p = &KeywordTable[i];
738 if (p->id == keyword)
740 name = p->name;
741 break;
744 return name;
747 static void UNUSED pt (tokenInfo *const token)
749 if (isType (token, TOKEN_NAME))
750 printf("type: %-12s: %-13s line: %lu\n",
751 tokenString (token->type), vStringValue (token->name),
752 token->lineNumber);
753 else if (isType (token, TOKEN_KEYWORD))
754 printf("type: %-12s: %-13s line: %lu\n",
755 tokenString (token->type), keywordString (token->keyword),
756 token->lineNumber);
757 else
758 printf("type: %-12s line: %lu\n",
759 tokenString (token->type), token->lineNumber);
762 static void UNUSED ps (statementInfo *const st)
764 unsigned int i;
765 printf("scope: %s decl: %s gotName: %s gotParenName: %s\n",
766 scopeString (st->scope), declString (st->declaration),
767 boolString (st->gotName), boolString (st->gotParenName));
768 printf("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
769 printf("access: %s default: %s\n", accessString (st->member.access),
770 accessString (st->member.accessDefault));
771 printf("token : ");
772 pt(activeToken (st));
773 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
775 printf("prev %u : ", i);
776 pt(prevToken (st, i));
778 printf("context: ");
779 pt(st->context);
782 #endif
785 * Statement management
788 static boolean isDataTypeKeyword (const tokenInfo *const token)
790 switch (token->keyword)
792 case KEYWORD_BOOLEAN:
793 case KEYWORD_BYTE:
794 case KEYWORD_CHAR:
795 case KEYWORD_DOUBLE:
796 case KEYWORD_FLOAT:
797 case KEYWORD_INT:
798 case KEYWORD_LONG:
799 case KEYWORD_SHORT:
800 case KEYWORD_VOID:
801 case KEYWORD_WCHAR_T:
802 case KEYWORD_SIZE_T:
803 return TRUE;
804 default:
805 return FALSE;
809 #if 0
810 static boolean isVariableKeyword (const tokenInfo *const token)
812 switch (token->keyword)
814 case KEYWORD_CONST:
815 case KEYWORD_EXTERN:
816 case KEYWORD_REGISTER:
817 case KEYWORD_STATIC:
818 case KEYWORD_VIRTUAL:
819 case KEYWORD_SIGNED:
820 case KEYWORD_UNSIGNED:
821 return TRUE;
822 default:
823 return FALSE;
826 #endif
828 static boolean isContextualKeyword (const tokenInfo *const token)
830 boolean result;
831 switch (token->keyword)
833 case KEYWORD_CLASS:
834 case KEYWORD_ENUM:
835 case KEYWORD_INTERFACE:
836 case KEYWORD_NAMESPACE:
837 case KEYWORD_STRUCT:
838 case KEYWORD_UNION:
840 result = TRUE;
841 break;
844 default:
846 result = FALSE;
847 break;
850 return result;
853 static boolean isContextualStatement (const statementInfo *const st)
855 boolean result = FALSE;
857 if (st != NULL)
859 if (isLanguage (Lang_vala))
861 /* All can be a contextual statement as properties can be of any type */
862 result = TRUE;
864 else
866 switch (st->declaration)
868 case DECL_CLASS:
869 case DECL_ENUM:
870 case DECL_INTERFACE:
871 case DECL_NAMESPACE:
872 case DECL_STRUCT:
873 case DECL_UNION:
875 result = TRUE;
876 break;
879 default:
881 result = FALSE;
882 break;
887 return result;
890 static boolean isMember (const statementInfo *const st)
892 boolean result;
893 if (isType (st->context, TOKEN_NAME))
894 result = TRUE;
895 else
896 result = isContextualStatement (st->parent);
897 return result;
900 static void initMemberInfo (statementInfo *const st)
902 accessType accessDefault = ACCESS_UNDEFINED;
904 if (st->parent != NULL) switch (st->parent->declaration)
906 case DECL_ENUM:
907 case DECL_NAMESPACE:
909 accessDefault = ACCESS_UNDEFINED;
910 break;
912 case DECL_CLASS:
914 if (isLanguage (Lang_java))
915 accessDefault = ACCESS_DEFAULT;
916 else
917 accessDefault = ACCESS_PRIVATE;
918 break;
920 case DECL_INTERFACE:
921 case DECL_STRUCT:
922 case DECL_UNION:
924 accessDefault = ACCESS_PUBLIC;
925 break;
927 default:
928 break;
930 st->member.accessDefault = accessDefault;
931 st->member.access = accessDefault;
934 static void reinitStatement (statementInfo *const st, const boolean partial)
936 unsigned int i;
938 if (! partial)
940 st->scope = SCOPE_GLOBAL;
941 if (isContextualStatement (st->parent))
942 st->declaration = DECL_BASE;
943 else
944 st->declaration = DECL_NONE;
946 st->gotParenName = FALSE;
947 st->implementation = IMP_DEFAULT;
948 st->gotArgs = FALSE;
949 st->gotName = FALSE;
950 st->nSemicolons = 0;
951 st->haveQualifyingName = FALSE;
952 st->argEndPosition = 0;
954 st->tokenIndex = 0;
955 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
957 initToken (st->token [i]);
960 initToken (st->context);
961 initToken (st->blockName);
962 vStringClear (st->parentClasses);
964 /* Init member info. */
965 if (! partial)
966 st->member.access = st->member.accessDefault;
968 /* Init first token */
969 if (!partial)
970 initToken(st->firstToken);
973 static void reinitStatementWithToken (statementInfo *const st,
974 tokenInfo *token, const boolean partial)
976 tokenInfo *const save = newToken ();
977 /* given token can be part of reinit statementInfo */
978 copyToken (save, token);
979 reinitStatement (st, partial);
980 token = activeToken (st);
981 copyToken (token, save);
982 deleteToken (save);
983 ++st->tokenIndex; /* this is quite safe because current tokenIndex = 0 */
986 static void initStatement (statementInfo *const st, statementInfo *const parent)
988 st->parent = parent;
989 initMemberInfo (st);
990 reinitStatement (st, FALSE);
991 if (parent)
993 const tokenInfo *const src = activeToken (parent);
994 tokenInfo *const dst = activeToken (st);
995 copyToken (dst, src);
996 st->tokenIndex++;
1001 * Tag generation functions
1003 static cKind cTagKind (const tagType type)
1005 cKind result = CK_UNDEFINED;
1006 switch (type)
1008 case TAG_CLASS: result = CK_CLASS; break;
1009 case TAG_ENUM: result = CK_ENUMERATION; break;
1010 case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
1011 case TAG_FUNCTION: result = CK_FUNCTION; break;
1012 case TAG_MEMBER: result = CK_MEMBER; break;
1013 case TAG_NAMESPACE: result = CK_NAMESPACE; break;
1014 case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
1015 case TAG_STRUCT: result = CK_STRUCT; break;
1016 case TAG_TYPEDEF: result = CK_TYPEDEF; break;
1017 case TAG_UNION: result = CK_UNION; break;
1018 case TAG_VARIABLE: result = CK_VARIABLE; break;
1019 case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
1021 default: Assert ("Bad C tag type" == NULL); break;
1023 return result;
1026 static csharpKind csharpTagKind (const tagType type)
1028 csharpKind result = CSK_UNDEFINED;
1029 switch (type)
1031 case TAG_CLASS: result = CSK_CLASS; break;
1032 case TAG_ENUM: result = CSK_ENUMERATION; break;
1033 case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
1034 case TAG_EVENT: result = CSK_EVENT; break;
1035 case TAG_FIELD: result = CSK_FIELD ; break;
1036 case TAG_INTERFACE: result = CSK_INTERFACE; break;
1037 case TAG_LOCAL: result = CSK_LOCAL; break;
1038 case TAG_METHOD: result = CSK_METHOD; break;
1039 case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
1040 case TAG_PROPERTY: result = CSK_PROPERTY; break;
1041 case TAG_STRUCT: result = CSK_STRUCT; break;
1042 case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
1044 default: Assert ("Bad C# tag type" == NULL); break;
1046 return result;
1049 static dKind dTagKind (const tagType type)
1051 dKind result = DK_UNDEFINED;
1052 switch (type)
1054 case TAG_CLASS: result = DK_CLASS; break;
1055 case TAG_ENUM: result = DK_ENUMERATION; break;
1056 case TAG_ENUMERATOR: result = DK_ENUMERATOR; break;
1057 case TAG_FUNCTION: result = DK_FUNCTION; break;
1058 case TAG_INTERFACE: result = DK_INTERFACE; break;
1059 case TAG_MEMBER: result = DK_MEMBER; break;
1060 case TAG_NAMESPACE: result = DK_NAMESPACE; break;
1061 case TAG_PROTOTYPE: result = DK_PROTOTYPE; break;
1062 case TAG_STRUCT: result = DK_STRUCT; break;
1063 case TAG_TYPEDEF: result = DK_TYPEDEF; break;
1064 case TAG_UNION: result = DK_UNION; break;
1065 case TAG_VARIABLE: result = DK_VARIABLE; break;
1066 case TAG_EXTERN_VAR: result = DK_EXTERN_VARIABLE; break;
1068 default: Assert ("Bad D tag type" == NULL); break;
1070 return result;
1073 static valaKind valaTagKind (const tagType type)
1075 valaKind result = VK_UNDEFINED;
1076 switch (type)
1078 case TAG_CLASS: result = VK_CLASS; break;
1079 case TAG_ENUM: result = VK_ENUMERATION; break;
1080 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
1081 case TAG_SIGNAL: result = VK_SIGNAL; break;
1082 case TAG_FIELD: result = VK_FIELD ; break;
1083 case TAG_INTERFACE: result = VK_INTERFACE; break;
1084 case TAG_LOCAL: result = VK_LOCAL; break;
1085 case TAG_METHOD: result = VK_METHOD; break;
1086 case TAG_NAMESPACE: result = VK_NAMESPACE; break;
1087 case TAG_PROPERTY: result = VK_PROPERTY; break;
1088 case TAG_STRUCT: result = VK_STRUCT; break;
1090 default: Assert ("Bad Vala tag type" == NULL); break;
1092 return result;
1095 static javaKind javaTagKind (const tagType type)
1097 javaKind result = JK_UNDEFINED;
1098 switch (type)
1100 case TAG_CLASS: result = JK_CLASS; break;
1101 case TAG_FIELD: result = JK_FIELD; break;
1102 case TAG_INTERFACE: result = JK_INTERFACE; break;
1103 case TAG_METHOD: result = JK_METHOD; break;
1104 case TAG_PACKAGE: result = JK_PACKAGE; break;
1105 case TAG_ENUM: result = JK_ENUMERATION; break;
1106 case TAG_ENUMERATOR: result = JK_ENUMERATOR; break;
1108 default: Assert ("Bad Java tag type" == NULL); break;
1110 return result;
1113 static const char *tagName (const tagType type)
1115 const char* result;
1116 if (isLanguage (Lang_java))
1117 result = JavaKinds [javaTagKind (type)].name;
1118 else if (isLanguage (Lang_csharp))
1119 result = CsharpKinds [csharpTagKind (type)].name;
1120 else if (isLanguage (Lang_d))
1121 result = DKinds [dTagKind (type)].name;
1122 else if (isLanguage (Lang_vala))
1123 result = ValaKinds [valaTagKind (type)].name;
1124 else
1125 result = CKinds [cTagKind (type)].name;
1126 return result;
1129 static int tagLetter (const tagType type)
1131 int result;
1132 if (isLanguage (Lang_csharp))
1133 result = CsharpKinds [csharpTagKind (type)].letter;
1134 else if (isLanguage (Lang_d))
1135 result = DKinds [dTagKind (type)].letter;
1136 else if (isLanguage (Lang_java))
1137 result = JavaKinds [javaTagKind (type)].letter;
1138 else if (isLanguage (Lang_vala))
1139 result = ValaKinds [valaTagKind (type)].letter;
1140 else
1141 result = CKinds [cTagKind (type)].letter;
1142 return result;
1146 static boolean includeTag (const tagType type, const boolean isFileScope)
1148 boolean result;
1149 if (isFileScope && ! Option.include.fileScope)
1150 result = FALSE;
1151 else if (isLanguage (Lang_java))
1152 result = JavaKinds [javaTagKind (type)].enabled;
1153 else
1154 result = CKinds [cTagKind (type)].enabled;
1155 return result;
1159 static tagType declToTagType (const declType declaration)
1161 tagType type = TAG_UNDEFINED;
1163 switch (declaration)
1165 case DECL_CLASS: type = TAG_CLASS; break;
1166 case DECL_ENUM: type = TAG_ENUM; break;
1167 case DECL_FUNCTION: type = TAG_FUNCTION; break;
1168 case DECL_FUNCTION_TEMPLATE: type = TAG_FUNCTION; break;
1169 case DECL_INTERFACE:type = TAG_INTERFACE; break;
1170 case DECL_NAMESPACE:type = TAG_NAMESPACE; break;
1171 case DECL_STRUCT: type = TAG_STRUCT; break;
1172 case DECL_UNION: type = TAG_UNION; break;
1174 default: Assert ("Unexpected declaration" == NULL); break;
1176 return type;
1179 static const char* accessField (const statementInfo *const st)
1181 const char* result = NULL;
1183 if ((isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite)) &&
1184 st->scope == SCOPE_FRIEND)
1185 result = "friend";
1186 else if (st->member.access != ACCESS_UNDEFINED)
1187 result = accessString (st->member.access);
1188 return result;
1191 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
1192 const tokenInfo *const nameToken,
1193 const statementInfo *const st, vString *const scope)
1195 /* For selected tag types, append an extension flag designating the
1196 * parent object in which the tag is defined.
1198 switch (type)
1200 default: break;
1202 case TAG_NAMESPACE:
1203 case TAG_CLASS:
1204 case TAG_ENUM:
1205 case TAG_ENUMERATOR:
1206 case TAG_FIELD:
1207 case TAG_FUNCTION:
1208 case TAG_INTERFACE:
1209 case TAG_MEMBER:
1210 case TAG_METHOD:
1211 case TAG_PROTOTYPE:
1212 case TAG_STRUCT:
1213 case TAG_TYPEDEF:
1214 case TAG_UNION:
1216 if (vStringLength (scope) > 0 &&
1217 (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1219 if (isType (st->context, TOKEN_NAME))
1220 tag->extensionFields.scope [0] = tagName (TAG_CLASS);
1221 else
1222 tag->extensionFields.scope [0] =
1223 tagName (declToTagType (parentDecl (st)));
1224 tag->extensionFields.scope [1] = vStringValue (scope);
1226 if ((type == TAG_CLASS || type == TAG_INTERFACE ||
1227 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
1229 tag->extensionFields.inheritance =
1230 vStringValue (st->parentClasses);
1232 if (st->implementation != IMP_DEFAULT &&
1233 (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
1234 isLanguage (Lang_java) || isLanguage (Lang_d) || isLanguage (Lang_ferite)))
1236 tag->extensionFields.implementation =
1237 implementationString (st->implementation);
1239 if (isMember (st))
1241 tag->extensionFields.access = accessField (st);
1243 if ((TRUE == st->gotArgs) && (TRUE == Option.extensionFields.argList) &&
1244 ((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type)))
1246 tag->extensionFields.signature = getArglistFromFilePos(
1247 tag->filePosition, tag->name);
1249 break;
1253 if ((TAG_FIELD == type) || (TAG_MEMBER == type) ||
1254 (TAG_EXTERN_VAR == type) || (TAG_TYPEDEF == type) ||
1255 (TAG_VARIABLE == type) || (TAG_METHOD == type) ||
1256 (TAG_PROTOTYPE == type) || (TAG_FUNCTION == type))
1258 if (((TOKEN_NAME == st->firstToken->type) || isDataTypeKeyword(st->firstToken))
1259 && (0 != strcmp(vStringValue(st->firstToken->name), tag->name)))
1261 tag->extensionFields.varType = getVarType(st, nameToken);
1266 static const char *getVarType (const statementInfo *const st,
1267 const tokenInfo *const nameToken)
1269 static vString *vt = NULL;
1270 unsigned int i;
1271 unsigned int end = st->tokenIndex;
1272 boolean seenType = FALSE;
1274 switch (st->declaration) {
1275 case DECL_BASE:
1276 case DECL_FUNCTION:
1277 case DECL_FUNCTION_TEMPLATE:
1278 break;
1279 default:
1280 return vStringValue(st->firstToken->name);
1283 if (vt == NULL)
1284 vt = vStringNew();
1285 else
1286 vStringClear(vt);
1288 /* find the end of the type signature in the token list */
1289 for (i = 0; i < st->tokenIndex; i++)
1291 const tokenInfo *const t = st->token[i];
1293 /* stop if we find the token used to generate the tag name, or
1294 * a name token in the middle yet not preceded by a scope separator */
1295 if ((t == nameToken ||
1296 (t->type == nameToken->type &&
1297 t->keyword == nameToken->keyword &&
1298 t->lineNumber == nameToken->lineNumber &&
1299 strcmp(vStringValue(t->name), vStringValue(nameToken->name)) == 0)) ||
1300 (t->type == TOKEN_NAME && seenType &&
1301 (i > 0 && st->token[i - 1]->type != TOKEN_DOUBLE_COLON)))
1303 break;
1305 if (t->type != TOKEN_DOUBLE_COLON)
1306 end = i + 1;
1307 if (t->type == TOKEN_NAME)
1308 seenType = TRUE;
1309 else if (t->type == TOKEN_KEYWORD && isDataTypeKeyword(t))
1310 seenType = TRUE;
1313 /* ugly historic workaround when we can't figure out the type */
1314 if (end < 2 && ! st->gotArgs)
1315 return vStringValue(st->firstToken->name);
1317 for (i = 0; i < end; i++)
1319 tokenInfo *t = st->token[i];
1321 switch (t->type)
1323 case TOKEN_NAME: /* user typename */
1324 break;
1325 case TOKEN_KEYWORD:
1326 if ((t->keyword != KEYWORD_EXTERN && t->keyword != KEYWORD_STATIC) && /* uninteresting keywords */
1327 (st->gotArgs ||
1328 /* ignore uninteresting keywords for non-functions */
1329 (t->keyword != KEYWORD_PUBLIC &&
1330 t->keyword != KEYWORD_PRIVATE &&
1331 t->keyword != KEYWORD_PROTECTED &&
1332 t->keyword != KEYWORD_FINAL &&
1333 t->keyword != KEYWORD_TYPEDEF &&
1334 /* hack for D static conditions */
1335 t->keyword != KEYWORD_IF)))
1337 break;
1339 continue;
1340 case TOKEN_STAR: vStringCatS(vt, " *"); continue;
1341 case TOKEN_ARRAY: vStringCatS(vt, "[]"); continue;
1342 case TOKEN_DOUBLE_COLON:
1343 vStringCatS(vt, "::");
1344 continue;
1345 default: continue;
1347 if (vStringLength(vt) > 0)
1348 if (isalpha(vStringValue(vt)[vStringLength(vt) - 1]))
1349 vStringPut(vt, ' ');
1350 vStringCat(vt, t->name);
1352 vStringTerminate(vt);
1353 return vStringValue(vt);
1356 static void addContextSeparator (vString *const scope)
1358 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
1359 vStringCatS (scope, "::");
1360 else if (isLanguage (Lang_java) || isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
1361 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1362 vStringCatS (scope, ".");
1365 static void findScopeHierarchy (vString *const string,
1366 const statementInfo *const st)
1368 const char* const anon = "<anonymous>";
1369 boolean nonAnonPresent = FALSE;
1371 vStringClear (string);
1372 if (isType (st->context, TOKEN_NAME))
1374 vStringCopy (string, st->context->name);
1375 nonAnonPresent = TRUE;
1377 if (st->parent != NULL)
1379 vString *temp = vStringNew ();
1380 const statementInfo *s;
1382 for (s = st->parent ; s != NULL ; s = s->parent)
1384 if (isContextualStatement (s) ||
1385 s->declaration == DECL_NAMESPACE)
1387 vStringCopy (temp, string);
1388 vStringClear (string);
1389 if (isType (s->blockName, TOKEN_NAME))
1391 if (isType (s->context, TOKEN_NAME) &&
1392 vStringLength (s->context->name) > 0)
1394 vStringCat (string, s->context->name);
1395 addContextSeparator (string);
1397 vStringCat (string, s->blockName->name);
1398 nonAnonPresent = TRUE;
1400 else
1401 vStringCopyS (string, anon);
1402 if (vStringLength (temp) > 0)
1403 addContextSeparator (string);
1404 vStringCat (string, temp);
1407 vStringDelete (temp);
1409 if (! nonAnonPresent)
1410 vStringClear (string);
1414 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1415 vString *const scope)
1417 if (Option.include.qualifiedTags &&
1418 scope != NULL && vStringLength (scope) > 0)
1420 vString *const scopedName = vStringNew ();
1422 if (type != TAG_ENUMERATOR)
1423 vStringCopy (scopedName, scope);
1424 else
1426 /* remove last component (i.e. enumeration name) from scope */
1427 const char* const sc = vStringValue (scope);
1428 const char* colon = strrchr (sc, ':');
1429 if (colon != NULL)
1431 while (*colon == ':' && colon > sc)
1432 --colon;
1433 vStringNCopy (scopedName, scope, colon + 1 - sc);
1436 if (vStringLength (scopedName) > 0)
1438 addContextSeparator (scopedName);
1439 vStringCatS (scopedName, e->name);
1440 e->name = vStringValue (scopedName);
1441 makeTagEntry (e);
1443 vStringDelete (scopedName);
1447 static void makeTag (const tokenInfo *const token,
1448 const statementInfo *const st,
1449 boolean isFileScope, const tagType type)
1451 #ifdef DEBUG_C
1452 printToken(token);
1453 fprintf(stderr, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
1454 printStatement(st);
1455 #endif
1456 /* Nothing is really of file scope when it appears in a header file.
1458 isFileScope = (boolean) (isFileScope && ! isHeaderFile ());
1460 if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 /* &&
1461 includeTag (type, isFileScope) */)
1463 vString *scope = vStringNew ();
1464 tagEntryInfo e;
1466 /* take only functions which are introduced by "function ..." */
1467 if (type == TAG_FUNCTION && isLanguage (Lang_ferite) &&
1468 strncmp("function", st->firstToken->name->buffer, 8) != 0)
1470 return;
1473 initTagEntry (&e, vStringValue (token->name));
1475 e.lineNumber = token->lineNumber;
1476 e.filePosition = token->filePosition;
1477 e.isFileScope = isFileScope;
1478 e.kindName = tagName (type);
1479 e.kind = tagLetter (type);
1481 findScopeHierarchy (scope, st);
1482 addOtherFields (&e, type, token, st, scope);
1484 #ifdef DEBUG_C
1485 printTagEntry(&e);
1486 #endif
1487 makeTagEntry (&e);
1488 if (NULL != TagEntryFunction)
1489 makeExtraTagEntry (type, &e, scope);
1490 vStringDelete (scope);
1491 if (NULL != e.extensionFields.signature)
1492 free((char *) e.extensionFields.signature);
1496 static boolean isValidTypeSpecifier (const declType declaration)
1498 boolean result;
1499 switch (declaration)
1501 case DECL_BASE:
1502 case DECL_CLASS:
1503 case DECL_ENUM:
1504 case DECL_STRUCT:
1505 case DECL_UNION:
1506 result = TRUE;
1507 break;
1509 default:
1510 result = FALSE;
1511 break;
1513 return result;
1516 static void qualifyEnumeratorTag (const statementInfo *const st,
1517 const tokenInfo *const nameToken)
1519 if (isType (nameToken, TOKEN_NAME))
1520 makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
1523 static void qualifyFunctionTag (const statementInfo *const st,
1524 const tokenInfo *const nameToken)
1526 if (isType (nameToken, TOKEN_NAME))
1528 const tagType type = (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1529 ? TAG_METHOD : TAG_FUNCTION;
1530 const boolean isFileScope =
1531 (boolean) (st->member.access == ACCESS_PRIVATE ||
1532 (!isMember (st) && st->scope == SCOPE_STATIC));
1534 makeTag (nameToken, st, isFileScope, type);
1538 static void qualifyFunctionDeclTag (const statementInfo *const st,
1539 const tokenInfo *const nameToken)
1541 if (! isType (nameToken, TOKEN_NAME))
1543 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1544 qualifyFunctionTag (st, nameToken);
1545 else if (st->scope == SCOPE_TYPEDEF)
1546 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1547 else if (isValidTypeSpecifier (st->declaration) &&
1548 ! (isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1549 makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
1552 static void qualifyCompoundTag (const statementInfo *const st,
1553 const tokenInfo *const nameToken)
1555 if (isType (nameToken, TOKEN_NAME))
1557 const tagType type = declToTagType (st->declaration);
1559 if (type != TAG_UNDEFINED)
1560 makeTag (nameToken, st, (boolean) (! isLanguage (Lang_java) &&
1561 ! isLanguage (Lang_csharp) &&
1562 ! isLanguage (Lang_vala)), type);
1566 static void qualifyBlockTag (statementInfo *const st,
1567 const tokenInfo *const nameToken)
1569 switch (st->declaration)
1571 case DECL_CLASS:
1572 case DECL_ENUM:
1573 case DECL_INTERFACE:
1574 case DECL_NAMESPACE:
1575 case DECL_STRUCT:
1576 case DECL_UNION:
1577 qualifyCompoundTag (st, nameToken);
1578 break;
1579 default: break;
1583 static void qualifyVariableTag (const statementInfo *const st,
1584 const tokenInfo *const nameToken)
1586 /* We have to watch that we do not interpret a declaration of the
1587 * form "struct tag;" as a variable definition. In such a case, the
1588 * token preceding the name will be a keyword.
1590 if (! isType (nameToken, TOKEN_NAME))
1592 else if (st->declaration == DECL_IGNORE)
1594 else if (st->scope == SCOPE_TYPEDEF)
1595 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1596 else if (st->declaration == DECL_PACKAGE)
1597 makeTag (nameToken, st, FALSE, TAG_PACKAGE);
1598 else if (st->declaration == DECL_MODULE) /* handle modules in D as namespaces */
1599 makeTag (nameToken, st, FALSE, TAG_NAMESPACE);
1600 else if (isValidTypeSpecifier (st->declaration))
1602 if (isMember (st))
1604 if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1605 makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1606 else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1607 makeTag (nameToken, st, TRUE, TAG_MEMBER);
1609 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1611 else
1613 if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1614 makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
1615 else
1616 makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC), TAG_VARIABLE);
1622 * Parsing functions
1625 static int skipToOneOf (const char *const chars)
1627 int c;
1629 c = cppGetc ();
1630 while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1632 return c;
1635 /* Skip to the next non-white character.
1637 static int skipToNonWhite (void)
1639 int c;
1643 c = cppGetc ();
1645 while (isspace (c));
1647 return c;
1650 /* Skips to the next brace in column 1. This is intended for cases where
1651 * preprocessor constructs result in unbalanced braces.
1653 static void skipToFormattedBraceMatch (void)
1655 int c, next;
1657 c = cppGetc ();
1658 next = cppGetc ();
1659 while (c != EOF && (c != '\n' || next != '}'))
1661 c = next;
1662 next = cppGetc ();
1666 /* Skip to the matching character indicated by the pair string. If skipping
1667 * to a matching brace and any brace is found within a different level of a
1668 * #if conditional statement while brace formatting is in effect, we skip to
1669 * the brace matched by its formatting. It is assumed that we have already
1670 * read the character which starts the group (i.e. the first character of
1671 * "pair").
1673 static void skipToMatch (const char *const pair)
1675 const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
1676 const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
1677 const unsigned int initialLevel = getDirectiveNestLevel ();
1678 const int begin = pair [0], end = pair [1];
1679 const unsigned long inputLineNumber = getInputLineNumber ();
1680 int matchLevel = 1;
1681 int c = '\0';
1682 if (isLanguage(Lang_d) && pair[0] == '<')
1683 return; /* ignore e.g. Foo!(x < 2) */
1684 while (matchLevel > 0 && (c = cppGetc ()) != EOF)
1686 if (c == begin)
1688 ++matchLevel;
1689 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1691 skipToFormattedBraceMatch ();
1692 break;
1695 else if (c == end)
1697 --matchLevel;
1698 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1700 skipToFormattedBraceMatch ();
1701 break;
1704 /* early out if matching "<>" and we encounter a ";" or "{" to mitigate
1705 * match problems with C++ generics containing a static expression like
1706 * foo<X<Y> bar;
1707 * normally neither ";" nor "{" could appear inside "<>" anyway. */
1708 else if (isLanguage (Lang_cpp) && begin == '<' &&
1709 (c == ';' || c == '{'))
1711 cppUngetc (c);
1712 break;
1715 if (c == EOF)
1717 verbose ("%s: failed to find match for '%c' at line %lu\n",
1718 getInputFileName (), begin, inputLineNumber);
1719 if (braceMatching)
1720 longjmp (Exception, (int) ExceptionBraceFormattingError);
1721 else
1722 longjmp (Exception, (int) ExceptionFormattingError);
1726 static void skipParens (void)
1728 const int c = skipToNonWhite ();
1730 if (c == '(')
1731 skipToMatch ("()");
1732 else
1733 cppUngetc (c);
1736 static void skipBraces (void)
1738 const int c = skipToNonWhite ();
1740 if (c == '{')
1741 skipToMatch ("{}");
1742 else
1743 cppUngetc (c);
1746 static keywordId analyzeKeyword (const char *const name)
1748 const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1750 /* ignore D @attributes and Java @annotations(...), but show them in function signatures */
1751 if ((isLanguage(Lang_d) || isLanguage(Lang_java)) && id == KEYWORD_NONE && name[0] == '@')
1753 skipParens(); /* if annotation has parameters, skip them */
1754 return KEYWORD_CONST;
1756 return id;
1759 static void analyzeIdentifier (tokenInfo *const token)
1761 char *const name = vStringValue (token->name);
1762 const char *replacement = NULL;
1763 boolean parensToo = FALSE;
1765 if (isLanguage (Lang_java) ||
1766 ! isIgnoreToken (name, &parensToo, &replacement))
1768 if (replacement != NULL)
1769 token->keyword = analyzeKeyword (replacement);
1770 else
1771 token->keyword = analyzeKeyword (vStringValue (token->name));
1773 if (token->keyword == KEYWORD_NONE)
1774 token->type = TOKEN_NAME;
1775 else
1776 token->type = TOKEN_KEYWORD;
1778 else
1780 initToken (token);
1781 if (parensToo)
1783 int c = skipToNonWhite ();
1785 if (c == '(')
1786 skipToMatch ("()");
1791 static void readIdentifier (tokenInfo *const token, const int firstChar)
1793 vString *const name = token->name;
1794 int c = firstChar;
1796 initToken (token);
1798 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1799 * the ~ and the class name. */
1800 if (isLanguage (Lang_cpp) && firstChar == '~')
1802 vStringPut (name, c);
1803 c = skipToNonWhite ();
1808 vStringPut (name, c);
1809 c = cppGetc ();
1810 } while (isident (c) || (isLanguage (Lang_vala) && '.' == c));
1811 vStringTerminate (name);
1812 cppUngetc (c); /* unget non-identifier character */
1814 /* Vala supports '?' at end of a type (with or without whitespace before) for nullable types */
1815 if (isLanguage (Lang_vala))
1817 c = skipToNonWhite ();
1818 if ('?' == c)
1819 vStringPut (name, c);
1820 else
1821 cppUngetc (c);
1824 analyzeIdentifier (token);
1827 static void readPackageName (tokenInfo *const token, const int firstChar)
1829 vString *const name = token->name;
1830 int c = firstChar;
1832 initToken (token);
1834 while (isident (c) || c == '.')
1836 vStringPut (name, c);
1837 c = cppGetc ();
1839 vStringTerminate (name);
1840 cppUngetc (c); /* unget non-package character */
1843 static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1845 st->declaration = declaration;
1847 if (declaration == DECL_NAMESPACE && !(isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1849 /* In C++ a namespace is specified one level at a time. */
1850 return;
1852 else
1854 /* In C#, a namespace can also be specified like a Java package name. */
1855 tokenInfo *const token = activeToken (st);
1856 Assert (isType (token, TOKEN_KEYWORD));
1857 readPackageName (token, skipToNonWhite ());
1858 token->type = TOKEN_NAME;
1859 st->gotName = TRUE;
1860 st->haveQualifyingName = TRUE;
1864 static void readPackage (statementInfo *const st)
1866 tokenInfo *const token = activeToken (st);
1867 Assert (isType (token, TOKEN_KEYWORD));
1868 readPackageName (token, skipToNonWhite ());
1869 token->type = TOKEN_NAME;
1870 if (isLanguage (Lang_d))
1871 st->declaration = DECL_MODULE;
1872 else
1873 st->declaration = DECL_PACKAGE;
1874 st->gotName = TRUE;
1875 st->haveQualifyingName = TRUE;
1878 static void processName (statementInfo *const st)
1880 Assert (isType (activeToken (st), TOKEN_NAME));
1881 if (st->gotName && st->declaration == DECL_NONE)
1882 st->declaration = DECL_BASE;
1883 st->gotName = TRUE;
1884 st->haveQualifyingName = TRUE;
1887 static void readOperator (statementInfo *const st)
1889 const char *const acceptable = "+-*/%^&|~!=<>,[]";
1890 const tokenInfo* const prev = prevToken (st,1);
1891 tokenInfo *const token = activeToken (st);
1892 vString *const name = token->name;
1893 int c = skipToNonWhite ();
1895 /* When we arrive here, we have the keyword "operator" in 'name'.
1897 if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1898 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1899 ; /* ignore "operator" keyword if preceded by these keywords */
1900 else if (c == '(')
1902 /* Verify whether this is a valid function call (i.e. "()") operator.
1904 if (cppGetc () == ')')
1906 vStringPut (name, ' '); /* always separate operator from keyword */
1907 c = skipToNonWhite ();
1908 if (c == '(')
1909 vStringCatS (name, "()");
1911 else
1913 skipToMatch ("()");
1914 c = cppGetc ();
1917 else if (isident1 (c))
1919 /* Handle "new" and "delete" operators, and conversion functions
1920 * (per 13.3.1.1.2 [2] of the C++ spec).
1922 boolean whiteSpace = TRUE; /* default causes insertion of space */
1925 if (isspace (c))
1926 whiteSpace = TRUE;
1927 else
1929 if (whiteSpace)
1931 vStringPut (name, ' ');
1932 whiteSpace = FALSE;
1934 vStringPut (name, c);
1936 c = cppGetc ();
1937 } while (! isOneOf (c, "(;") && c != EOF);
1938 vStringTerminate (name);
1940 else if (isOneOf (c, acceptable))
1942 vStringPut (name, ' '); /* always separate operator from keyword */
1945 vStringPut (name, c);
1946 c = cppGetc ();
1947 } while (isOneOf (c, acceptable));
1948 vStringTerminate (name);
1951 cppUngetc (c);
1953 token->type = TOKEN_NAME;
1954 token->keyword = KEYWORD_NONE;
1955 processName (st);
1958 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1960 dest->type = src->type;
1961 dest->keyword = src->keyword;
1962 dest->filePosition = src->filePosition;
1963 dest->lineNumber = src->lineNumber;
1964 vStringCopy (dest->name, src->name);
1967 static void setAccess (statementInfo *const st, const accessType laccess)
1969 if (isMember (st))
1971 if (isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite))
1973 int c = skipToNonWhite ();
1975 if (c == ':')
1976 reinitStatementWithToken (st, prevToken (st, 1), FALSE);
1977 else
1978 cppUngetc (c);
1980 st->member.accessDefault = laccess;
1982 st->member.access = laccess;
1986 static void discardTypeList (tokenInfo *const token)
1988 int c = skipToNonWhite ();
1989 while (isident1 (c))
1991 readIdentifier (token, c);
1992 c = skipToNonWhite ();
1993 if (c == '.' || c == ',')
1994 c = skipToNonWhite ();
1996 cppUngetc (c);
1999 static void addParentClass (statementInfo *const st, tokenInfo *const token)
2001 if (vStringLength (token->name) > 0 &&
2002 vStringLength (st->parentClasses) > 0)
2004 vStringPut (st->parentClasses, ',');
2006 vStringCat (st->parentClasses, token->name);
2009 static void readParents (statementInfo *const st, const int qualifier)
2011 tokenInfo *const token = newToken ();
2012 tokenInfo *const parent = newToken ();
2013 int c;
2017 c = skipToNonWhite ();
2018 if (isident1 (c))
2020 readIdentifier (token, c);
2021 if (isType (token, TOKEN_NAME))
2022 vStringCat (parent->name, token->name);
2023 else
2025 addParentClass (st, parent);
2026 initToken (parent);
2029 else if (c == qualifier)
2030 vStringPut (parent->name, c);
2031 else if (c == '<')
2032 skipToMatch ("<>");
2033 else if (isType (token, TOKEN_NAME))
2035 addParentClass (st, parent);
2036 initToken (parent);
2038 } while (c != '{' && c != EOF);
2039 cppUngetc (c);
2040 deleteToken (parent);
2041 deleteToken (token);
2044 static void checkIsClassEnum (statementInfo *const st, const declType decl)
2046 if (! isLanguage (Lang_cpp) || st->declaration != DECL_ENUM)
2047 st->declaration = decl;
2050 static void processToken (tokenInfo *const token, statementInfo *const st)
2052 switch (token->keyword) /* is it a reserved word? */
2054 default: break;
2056 case KEYWORD_NONE: processName (st); break;
2057 case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
2058 case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
2059 case KEYWORD_CATCH: skipParens (); skipBraces (); break;
2060 case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
2061 case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break;
2062 case KEYWORD_CONST: st->declaration = DECL_BASE; break;
2063 case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
2064 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
2065 case KEYWORD_EXTENDS: readParents (st, '.');
2066 setToken (st, TOKEN_NONE); break;
2067 case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
2068 case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
2069 case KEYWORD_IMPLEMENTS:readParents (st, '.');
2070 setToken (st, TOKEN_NONE); break;
2071 case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
2072 case KEYWORD_INT: st->declaration = DECL_BASE; break;
2073 case KEYWORD_BOOLEAN: st->declaration = DECL_BASE; break;
2074 case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
2075 case KEYWORD_SIZE_T: st->declaration = DECL_BASE; break;
2076 case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
2077 case KEYWORD_LONG: st->declaration = DECL_BASE; break;
2078 case KEYWORD_OPERATOR: readOperator (st); break;
2079 case KEYWORD_MODULE: readPackage (st); break;
2080 case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
2081 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
2082 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
2083 case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
2084 case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
2085 case KEYWORD_STRUCT: checkIsClassEnum (st, DECL_STRUCT); break;
2086 case KEYWORD_STATIC_ASSERT: skipParens (); break;
2087 case KEYWORD_THROWS: discardTypeList (token); break;
2088 case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
2089 case KEYWORD_UNION: st->declaration = DECL_UNION; break;
2090 case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
2091 case KEYWORD_USING: st->declaration = DECL_IGNORE; break;
2092 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
2093 case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
2094 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
2096 case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
2097 case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
2098 case KEYWORD_EVENT:
2100 if (isLanguage (Lang_csharp))
2101 st->declaration = DECL_EVENT;
2102 break;
2104 case KEYWORD_SIGNAL:
2106 if (isLanguage (Lang_vala))
2107 st->declaration = DECL_SIGNAL;
2108 break;
2110 case KEYWORD_EXTERN:
2112 if (! isLanguage (Lang_csharp) || !st->gotName)
2114 /*reinitStatement (st, FALSE);*/
2115 st->scope = SCOPE_EXTERN;
2116 st->declaration = DECL_BASE;
2118 break;
2120 case KEYWORD_STATIC:
2122 if (! isLanguage (Lang_java) && ! isLanguage (Lang_csharp) && ! isLanguage (Lang_vala))
2124 /*reinitStatement (st, FALSE);*/
2125 st->scope = SCOPE_STATIC;
2126 st->declaration = DECL_BASE;
2128 break;
2130 case KEYWORD_IF:
2131 if (isLanguage (Lang_d))
2132 { /* static if (is(typeof(__traits(getMember, a, name)) == function)) */
2133 int c = skipToNonWhite ();
2134 if (c == '(')
2135 skipToMatch ("()");
2137 break;
2142 * Parenthesis handling functions
2145 static void restartStatement (statementInfo *const st)
2147 tokenInfo *const save = newToken ();
2148 tokenInfo *token = activeToken (st);
2150 copyToken (save, token);
2151 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
2152 reinitStatement (st, FALSE);
2153 token = activeToken (st);
2154 copyToken (token, save);
2155 deleteToken (save);
2156 processToken (token, st);
2159 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
2161 * mem-initializer-list:
2162 * mem-initializer, mem-initializer-list
2164 * mem-initializer:
2165 * [::] [nested-name-spec] class-name (...)
2166 * identifier
2168 static void skipMemIntializerList (tokenInfo *const token)
2170 int c;
2174 c = skipToNonWhite ();
2175 while (isident1 (c) || c == ':')
2177 if (c != ':')
2178 readIdentifier (token, c);
2179 c = skipToNonWhite ();
2181 if (c == '<')
2183 skipToMatch ("<>");
2184 c = skipToNonWhite ();
2186 if (c == '(')
2188 skipToMatch ("()");
2189 c = skipToNonWhite ();
2191 } while (c == ',');
2192 cppUngetc (c);
2195 static void skipMacro (statementInfo *const st)
2197 tokenInfo *const prev2 = prevToken (st, 2);
2199 if (isType (prev2, TOKEN_NAME))
2200 retardToken (st);
2201 skipToMatch ("()");
2204 static boolean isDPostArgumentToken(tokenInfo *const token)
2206 switch (token->keyword)
2208 /* Note: some other keywords e.g. immutable are parsed as
2209 * KEYWORD_CONST - see initializeDParser */
2210 case KEYWORD_CONST:
2211 /* template constraint */
2212 case KEYWORD_IF:
2213 /* contracts */
2214 case KEYWORD_IN:
2215 case KEYWORD_OUT:
2216 case KEYWORD_BODY:
2217 return TRUE;
2218 default:
2219 break;
2221 /* @attributes */
2222 if (vStringValue(token->name)[0] == '@')
2223 return TRUE;
2224 return FALSE;
2227 /* Skips over characters following the parameter list. This will be either
2228 * non-ANSI style function declarations or C++ stuff. Our choices:
2230 * C (K&R):
2231 * int func ();
2232 * int func (one, two) int one; float two; {...}
2233 * C (ANSI):
2234 * int func (int one, float two);
2235 * int func (int one, float two) {...}
2236 * C++:
2237 * int foo (...) [const|volatile] [throw (...)];
2238 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2239 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2240 * catch (...) {...}
2242 static boolean skipPostArgumentStuff (statementInfo *const st,
2243 parenInfo *const info)
2245 tokenInfo *const token = activeToken (st);
2246 unsigned int parameters = info->parameterCount;
2247 unsigned int elementCount = 0;
2248 boolean restart = FALSE;
2249 boolean end = FALSE;
2250 int c = skipToNonWhite ();
2254 switch (c)
2256 case ')': break;
2257 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
2258 case '[': skipToMatch ("[]"); break;
2259 case '=': cppUngetc (c); end = TRUE; break;
2260 case '{': cppUngetc (c); end = TRUE; break;
2261 case '}': cppUngetc (c); end = TRUE; break;
2263 case '(':
2265 if (elementCount > 0)
2266 ++elementCount;
2267 skipToMatch ("()");
2268 break;
2271 case ';':
2273 if (parameters == 0 || elementCount < 2)
2275 cppUngetc (c);
2276 end = TRUE;
2278 else if (--parameters == 0)
2279 end = TRUE;
2280 break;
2283 default:
2285 if (isident1 (c))
2287 readIdentifier (token, c);
2288 if (isLanguage(Lang_d) && isDPostArgumentToken(token))
2289 token->keyword = KEYWORD_CONST;
2291 switch (token->keyword)
2293 case KEYWORD_ATTRIBUTE: skipParens (); break;
2294 case KEYWORD_THROW: skipParens (); break;
2295 case KEYWORD_CONST: break;
2296 case KEYWORD_NOEXCEPT: break;
2297 case KEYWORD_TRY: break;
2298 case KEYWORD_VOLATILE: break;
2300 case KEYWORD_CATCH: case KEYWORD_CLASS:
2301 case KEYWORD_EXPLICIT: case KEYWORD_EXTERN:
2302 case KEYWORD_FRIEND: case KEYWORD_INLINE:
2303 case KEYWORD_MUTABLE: case KEYWORD_NAMESPACE:
2304 case KEYWORD_NEW: case KEYWORD_OPERATOR:
2305 case KEYWORD_OVERLOAD: case KEYWORD_PRIVATE:
2306 case KEYWORD_PROTECTED: case KEYWORD_PUBLIC:
2307 case KEYWORD_STATIC: case KEYWORD_TEMPLATE:
2308 case KEYWORD_TYPEDEF: case KEYWORD_TYPENAME:
2309 case KEYWORD_USING: case KEYWORD_VIRTUAL:
2310 /* Never allowed within parameter declarations.
2312 restart = TRUE;
2313 end = TRUE;
2314 break;
2316 default:
2317 /* "override" and "final" are only keywords in the declaration of a virtual
2318 * member function, so need to be handled specially, not as keywords */
2319 if (isLanguage(Lang_cpp) && isType (token, TOKEN_NAME) &&
2320 (strcmp ("override", vStringValue (token->name)) == 0 ||
2321 strcmp ("final", vStringValue (token->name)) == 0))
2323 else if (isType (token, TOKEN_NONE))
2325 else if (info->isKnrParamList && info->parameterCount > 0)
2326 ++elementCount;
2327 else
2329 /* If we encounter any other identifier immediately
2330 * following an empty parameter list, this is almost
2331 * certainly one of those Microsoft macro "thingies"
2332 * that the automatic source code generation sticks
2333 * in. Terminate the current statement.
2335 restart = TRUE;
2336 end = TRUE;
2338 break;
2343 if (! end)
2345 c = skipToNonWhite ();
2346 if (c == EOF)
2347 end = TRUE;
2349 } while (! end);
2351 if (restart)
2352 restartStatement (st);
2353 else
2354 setToken (st, TOKEN_NONE);
2355 return (boolean) (c != EOF);
2358 static void skipJavaThrows (statementInfo *const st)
2360 tokenInfo *const token = activeToken (st);
2361 int c = skipToNonWhite ();
2363 if (isident1 (c))
2365 readIdentifier (token, c);
2366 if (token->keyword == KEYWORD_THROWS)
2370 c = skipToNonWhite ();
2371 if (isident1 (c))
2373 readIdentifier (token, c);
2374 c = skipToNonWhite ();
2376 } while (c == '.' || c == ',');
2379 cppUngetc (c);
2380 setToken (st, TOKEN_NONE);
2383 static void skipValaPostParens (statementInfo *const st)
2385 tokenInfo *const token = activeToken (st);
2386 int c = skipToNonWhite ();
2388 while (isident1 (c))
2390 readIdentifier (token, c);
2391 if (token->keyword == KEYWORD_ATTRIBUTE)
2393 /* parse contracts */
2394 skipParens ();
2395 c = skipToNonWhite ();
2397 else if (token->keyword == KEYWORD_THROWS)
2401 c = skipToNonWhite ();
2402 if (isident1 (c))
2404 readIdentifier (token, c);
2405 c = skipToNonWhite ();
2407 } while (c == '.' || c == ',');
2409 else
2410 break;
2412 cppUngetc (c);
2413 setToken (st, TOKEN_NONE);
2416 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2418 const unsigned long inputLineNumber = getInputLineNumber ();
2419 int c = skipToNonWhite ();
2421 cppUngetc (c);
2422 if (isOneOf (c, "{;,="))
2424 else if (isLanguage (Lang_java))
2425 skipJavaThrows (st);
2426 else if (isLanguage (Lang_vala))
2427 skipValaPostParens(st);
2428 else
2430 if (! skipPostArgumentStuff (st, info))
2432 verbose (
2433 "%s: confusing argument declarations beginning at line %lu\n",
2434 getInputFileName (), inputLineNumber);
2435 longjmp (Exception, (int) ExceptionFormattingError);
2440 static int parseParens (statementInfo *const st, parenInfo *const info)
2442 tokenInfo *const token = activeToken (st);
2443 unsigned int identifierCount = 0;
2444 unsigned int depth = 1;
2445 boolean firstChar = TRUE;
2446 int nextChar = '\0';
2448 info->parameterCount = 1;
2451 int c = skipToNonWhite ();
2453 switch (c)
2455 case '&':
2456 case '*':
2458 /* DEBUG_PRINT("parseParens, po++\n"); */
2459 info->isKnrParamList = FALSE;
2460 if (identifierCount == 0)
2461 info->isParamList = FALSE;
2462 initToken (token);
2463 break;
2465 case ':':
2467 info->isKnrParamList = FALSE;
2468 break;
2470 case '.':
2472 info->isNameCandidate = FALSE;
2473 info->isKnrParamList = FALSE;
2474 break;
2476 case ',':
2478 info->isNameCandidate = FALSE;
2479 if (info->isKnrParamList)
2481 ++info->parameterCount;
2482 identifierCount = 0;
2484 break;
2486 case '=':
2488 info->isKnrParamList = FALSE;
2489 info->isNameCandidate = FALSE;
2490 if (firstChar)
2492 info->isParamList = FALSE;
2493 skipMacro (st);
2494 depth = 0;
2496 break;
2498 case '[':
2500 info->isKnrParamList = FALSE;
2501 skipToMatch ("[]");
2502 break;
2504 case '<':
2506 info->isKnrParamList = FALSE;
2507 skipToMatch ("<>");
2508 break;
2510 case ')':
2512 if (firstChar)
2513 info->parameterCount = 0;
2514 --depth;
2515 break;
2517 case '(':
2519 info->isKnrParamList = FALSE;
2520 if (firstChar)
2522 info->isNameCandidate = FALSE;
2523 cppUngetc (c);
2524 skipMacro (st);
2525 depth = 0;
2527 else if (isType (token, TOKEN_PAREN_NAME))
2529 c = skipToNonWhite ();
2530 if (c == '*') /* check for function pointer */
2532 skipToMatch ("()");
2533 c = skipToNonWhite ();
2534 if (c == '(')
2535 skipToMatch ("()");
2537 else
2539 cppUngetc (c);
2540 cppUngetc ('(');
2541 info->nestedArgs = TRUE;
2544 else
2545 ++depth;
2546 break;
2549 default:
2551 if (isident1 (c))
2553 if (++identifierCount > 1)
2554 info->isKnrParamList = FALSE;
2555 readIdentifier (token, c);
2556 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2557 token->type = TOKEN_PAREN_NAME;
2558 else if (isType (token, TOKEN_KEYWORD))
2560 info->isKnrParamList = FALSE;
2561 info->isNameCandidate = FALSE;
2564 else if (isLanguage(Lang_d) && c == '!')
2565 { /* D template instantiation */
2566 info->isNameCandidate = FALSE;
2567 info->isKnrParamList = FALSE;
2569 else
2571 info->isParamList = FALSE;
2572 info->isKnrParamList = FALSE;
2573 info->isNameCandidate = FALSE;
2574 info->invalidContents = TRUE;
2576 break;
2579 firstChar = FALSE;
2580 } while (! info->nestedArgs && depth > 0 &&
2581 (info->isKnrParamList || info->isNameCandidate));
2583 if (! info->nestedArgs) while (depth > 0)
2585 skipToMatch ("()");
2586 --depth;
2588 if (st->argEndPosition == 0)
2589 st->argEndPosition = mio_tell (File.mio);
2591 if (! info->isNameCandidate)
2592 initToken (token);
2594 return nextChar;
2597 static void initParenInfo (parenInfo *const info)
2599 info->isParamList = TRUE;
2600 info->isKnrParamList = TRUE;
2601 info->isNameCandidate = TRUE;
2602 info->invalidContents = FALSE;
2603 info->nestedArgs = FALSE;
2604 info->parameterCount = 0;
2607 static void analyzeParens (statementInfo *const st)
2609 tokenInfo *const prev = prevToken (st, 1);
2611 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2613 tokenInfo *const token = activeToken (st);
2614 parenInfo info;
2615 int c;
2617 initParenInfo (&info);
2618 parseParens (st, &info);
2620 c = skipToNonWhite ();
2622 cppUngetc (c);
2623 if (info.invalidContents)
2625 reinitStatement (st, FALSE);
2627 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2628 ! st->gotParenName &&
2629 (! info.isParamList || ! st->haveQualifyingName ||
2630 c == '(' ||
2631 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2632 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2634 token->type = TOKEN_NAME;
2635 processName (st);
2636 st->gotParenName = TRUE;
2637 if (isLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME))
2639 st->declaration = DECL_FUNCTION_TEMPLATE;
2640 copyToken (st->blockName, prev);
2643 else if (! st->gotArgs && info.isParamList)
2645 st->gotArgs = TRUE;
2646 setToken (st, TOKEN_ARGS);
2647 advanceToken (st);
2648 analyzePostParens (st, &info);
2650 else
2652 setToken (st, TOKEN_NONE);
2658 * Token parsing functions
2661 static void addContext (statementInfo *const st, const tokenInfo* const token)
2663 if (isType (token, TOKEN_NAME))
2665 if (vStringLength (st->context->name) > 0)
2667 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
2668 vStringCatS (st->context->name, "::");
2669 else if (isLanguage (Lang_java) ||
2670 isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
2671 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
2672 vStringCatS (st->context->name, ".");
2674 vStringCat (st->context->name, token->name);
2675 st->context->type = TOKEN_NAME;
2679 static boolean inheritingDeclaration (declType decl)
2681 /* enum base types */
2682 if (decl == DECL_ENUM)
2684 return (boolean) (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) ||
2685 isLanguage (Lang_d));
2687 return (boolean) (
2688 decl == DECL_CLASS ||
2689 decl == DECL_STRUCT ||
2690 decl == DECL_INTERFACE);
2693 static void processColon (statementInfo *const st)
2695 int c = cppGetc ();
2696 const boolean doubleColon = (boolean) (c == ':');
2698 if (doubleColon)
2700 setToken (st, TOKEN_DOUBLE_COLON);
2701 st->haveQualifyingName = FALSE;
2703 else
2705 cppUngetc (c);
2706 if ((isLanguage (Lang_cpp) || isLanguage (Lang_csharp) || isLanguage (Lang_d) ||
2707 isLanguage (Lang_vala)) &&
2708 inheritingDeclaration (st->declaration))
2710 readParents (st, ':');
2712 else if (parentDecl (st) == DECL_STRUCT || parentDecl (st) == DECL_CLASS)
2714 c = skipToOneOf (",;");
2715 if (c == ',')
2716 setToken (st, TOKEN_COMMA);
2717 else if (c == ';')
2718 setToken (st, TOKEN_SEMICOLON);
2720 else
2722 const tokenInfo *const prev = prevToken (st, 1);
2723 const tokenInfo *const prev2 = prevToken (st, 2);
2724 if (prev->keyword == KEYWORD_DEFAULT ||
2725 prev2->keyword == KEYWORD_CASE ||
2726 st->parent != NULL)
2728 reinitStatement (st, FALSE);
2734 /* Skips over any initializing value which may follow an '=' character in a
2735 * variable definition.
2737 static int skipInitializer (statementInfo *const st)
2739 boolean done = FALSE;
2740 int c;
2742 while (! done)
2744 c = skipToNonWhite ();
2746 if (c == EOF)
2747 longjmp (Exception, (int) ExceptionFormattingError);
2748 else switch (c)
2750 case ',':
2751 case ';': done = TRUE; break;
2753 case '0':
2754 if (st->implementation == IMP_VIRTUAL)
2755 st->implementation = IMP_PURE_VIRTUAL;
2756 break;
2758 case '[': skipToMatch ("[]"); break;
2759 case '(': skipToMatch ("()"); break;
2760 case '{': skipToMatch ("{}"); break;
2762 case '}':
2763 if (insideEnumBody (st))
2764 done = TRUE;
2765 else if (! isBraceFormat ())
2767 verbose ("%s: unexpected closing brace at line %lu\n",
2768 getInputFileName (), getInputLineNumber ());
2769 longjmp (Exception, (int) ExceptionBraceFormattingError);
2771 break;
2773 default: break;
2776 return c;
2779 static void processInitializer (statementInfo *const st)
2781 const boolean inEnumBody = insideEnumBody (st);
2782 const int c = skipInitializer (st);
2784 if (c == ';')
2785 setToken (st, TOKEN_SEMICOLON);
2786 else if (c == ',')
2787 setToken (st, TOKEN_COMMA);
2788 else if (c == '}' && inEnumBody)
2790 cppUngetc (c);
2791 setToken (st, TOKEN_COMMA);
2793 if (st->scope == SCOPE_EXTERN)
2794 st->scope = SCOPE_GLOBAL;
2797 static void parseIdentifier (statementInfo *const st, const int c)
2799 tokenInfo *const token = activeToken (st);
2801 readIdentifier (token, c);
2802 if (! isType (token, TOKEN_NONE))
2803 processToken (token, st);
2806 static void parseGeneralToken (statementInfo *const st, const int c)
2808 const tokenInfo *const prev = prevToken (st, 1);
2810 if (isident1(c))
2812 parseIdentifier (st, c);
2813 if (isType (st->context, TOKEN_NAME) &&
2814 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2816 initToken (st->context);
2819 else if (isExternCDecl (st, c))
2821 st->declaration = DECL_NOMANGLE;
2822 st->scope = SCOPE_GLOBAL;
2826 /* Reads characters from the pre-processor and assembles tokens, setting
2827 * the current statement state.
2829 static void nextToken (statementInfo *const st)
2831 int c;
2832 tokenInfo *token = activeToken (st);
2835 c = skipToNonWhite();
2836 switch (c)
2838 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2839 case '(': analyzeParens (st); token = activeToken (st); break;
2840 case '*': setToken (st, TOKEN_STAR); break;
2841 case ',': setToken (st, TOKEN_COMMA); break;
2842 case ':': processColon (st); break;
2843 case ';': setToken (st, TOKEN_SEMICOLON); break;
2844 case '<': skipToMatch ("<>"); break;
2845 case '=': processInitializer (st); break;
2846 case '[':
2847 /* Hack for Vala: [..] can be a function attribute.
2848 * Seems not to have bad side effects, but have to test it more. */
2849 if (!isLanguage (Lang_vala))
2850 setToken (st, TOKEN_ARRAY);
2851 skipToMatch ("[]");
2852 break;
2853 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2854 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2855 default: parseGeneralToken (st, c); break;
2857 } while (isType (token, TOKEN_NONE));
2859 if (isType (token, TOKEN_SEMICOLON) && st->parent)
2860 st->parent->nSemicolons ++;
2862 /* We want to know about non-keyword variable types */
2863 if (TOKEN_NONE == st->firstToken->type)
2865 if ((TOKEN_NAME == token->type) || isDataTypeKeyword(token))
2866 copyToken(st->firstToken, token);
2871 * Scanning support functions
2873 static unsigned int contextual_fake_count = 0;
2874 static statementInfo *CurrentStatement = NULL;
2876 static statementInfo *newStatement (statementInfo *const parent)
2878 statementInfo *const st = xMalloc (1, statementInfo);
2879 unsigned int i;
2881 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2882 st->token [i] = newToken ();
2884 st->context = newToken ();
2885 st->blockName = newToken ();
2886 st->parentClasses = vStringNew ();
2887 st->firstToken = newToken();
2889 initStatement (st, parent);
2890 CurrentStatement = st;
2892 return st;
2895 static void deleteStatement (void)
2897 statementInfo *const st = CurrentStatement;
2898 statementInfo *const parent = st->parent;
2899 unsigned int i;
2901 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2903 deleteToken(st->token[i]); st->token[i] = NULL;
2905 deleteToken(st->blockName); st->blockName = NULL;
2906 deleteToken(st->context); st->context = NULL;
2907 vStringDelete(st->parentClasses); st->parentClasses = NULL;
2908 deleteToken(st->firstToken);
2909 eFree (st);
2910 CurrentStatement = parent;
2913 static void deleteAllStatements (void)
2915 while (CurrentStatement != NULL)
2916 deleteStatement ();
2919 static boolean isStatementEnd (const statementInfo *const st)
2921 const tokenInfo *const token = activeToken (st);
2922 boolean isEnd;
2924 if (isType (token, TOKEN_SEMICOLON))
2925 isEnd = TRUE;
2926 else if (isType (token, TOKEN_BRACE_CLOSE))
2927 /* Java, D, C#, Vala do not require semicolons to end a block. Neither do
2928 * C++ namespaces. All other blocks require a semicolon to terminate them.
2930 isEnd = (boolean) (isLanguage (Lang_java) || isLanguage (Lang_d) ||
2931 isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
2932 ! isContextualStatement (st));
2933 else
2934 isEnd = FALSE;
2936 return isEnd;
2939 static void checkStatementEnd (statementInfo *const st)
2941 const tokenInfo *const token = activeToken (st);
2942 boolean comma = isType (token, TOKEN_COMMA);
2944 if (comma || isStatementEnd (st))
2946 reinitStatementWithToken (st, activeToken (st), comma);
2948 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2949 cppEndStatement ();
2951 else
2953 cppBeginStatement ();
2954 advanceToken (st);
2958 static void nest (statementInfo *const st, const unsigned int nestLevel)
2960 switch (st->declaration)
2962 case DECL_CLASS:
2963 case DECL_ENUM:
2964 case DECL_INTERFACE:
2965 case DECL_NAMESPACE:
2966 case DECL_NOMANGLE:
2967 case DECL_STRUCT:
2968 case DECL_UNION:
2969 createTags (nestLevel, st);
2970 break;
2971 default:
2972 skipToMatch ("{}");
2973 break;
2975 advanceToken (st);
2976 setToken (st, TOKEN_BRACE_CLOSE);
2979 static void tagCheck (statementInfo *const st)
2981 const tokenInfo *const token = activeToken (st);
2982 const tokenInfo *const prev = prevToken (st, 1);
2983 const tokenInfo *const prev2 = prevToken (st, 2);
2985 switch (token->type)
2987 case TOKEN_NAME:
2989 if (insideEnumBody (st) &&
2990 /* Java enumerations can contain members after a semicolon */
2991 (! isLanguage(Lang_java) || st->parent->nSemicolons < 1))
2992 qualifyEnumeratorTag (st, token);
2993 break;
2995 #if 0
2996 case TOKEN_PACKAGE:
2998 if (st->haveQualifyingName)
2999 makeTag (token, st, FALSE, TAG_PACKAGE);
3000 break;
3002 #endif
3003 case TOKEN_BRACE_OPEN:
3005 if (isType (prev, TOKEN_ARGS))
3007 if (st->declaration == DECL_FUNCTION_TEMPLATE)
3008 qualifyFunctionTag (st, st->blockName);
3009 else if (st->haveQualifyingName)
3011 if (isType (prev2, TOKEN_NAME))
3012 copyToken (st->blockName, prev2);
3013 /* D structure templates */
3014 if (isLanguage (Lang_d) &&
3015 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT ||
3016 st->declaration == DECL_INTERFACE || st->declaration == DECL_NAMESPACE))
3017 qualifyBlockTag (st, prev2);
3018 else
3020 st->declaration = DECL_FUNCTION;
3021 qualifyFunctionTag (st, prev2);
3025 else if (isContextualStatement (st))
3027 tokenInfo *name_token = (tokenInfo *)prev;
3028 boolean free_name_token = FALSE;
3030 /* C++ 11 allows class <name> final { ... } */
3031 if (isLanguage (Lang_cpp) && isType (prev, TOKEN_NAME) &&
3032 strcmp("final", vStringValue(prev->name)) == 0 &&
3033 isType(prev2, TOKEN_NAME))
3035 name_token = (tokenInfo *)prev2;
3036 copyToken (st->blockName, name_token);
3038 else if (isType (name_token, TOKEN_NAME))
3040 if (!isLanguage (Lang_vala))
3041 copyToken (st->blockName, name_token);
3042 else
3044 switch (st->declaration)
3046 case DECL_CLASS:
3047 case DECL_ENUM:
3048 case DECL_INTERFACE:
3049 case DECL_NAMESPACE:
3050 case DECL_STRUCT:
3051 copyToken (st->blockName, name_token);
3052 break;
3054 /* anything else can be a property */
3055 default:
3056 /* makeTag (prev, st, FALSE, TAG_PROPERTY); */
3057 /* FIXME: temporary hack to get properties shown */
3058 makeTag (prev, st, FALSE, TAG_FIELD);
3059 break;
3063 else if (isLanguage (Lang_csharp))
3064 makeTag (prev, st, FALSE, TAG_PROPERTY);
3065 else
3067 tokenInfo *contextual_token = (tokenInfo *)prev;
3068 if(isContextualKeyword (contextual_token))
3070 char buffer[64];
3072 name_token = newToken ();
3073 free_name_token = TRUE;
3074 copyToken (name_token, contextual_token);
3076 sprintf(buffer, "anon_%s_%d", name_token->name->buffer, contextual_fake_count++);
3077 vStringClear(name_token->name);
3078 vStringCatS(name_token->name, buffer);
3080 name_token->type = TOKEN_NAME;
3081 name_token->keyword = KEYWORD_NONE;
3083 advanceToken (st);
3084 contextual_token = activeToken (st);
3085 copyToken (contextual_token, token);
3086 copyToken ((tokenInfo *const)token, name_token);
3087 copyToken (st->blockName, name_token);
3088 copyToken (st->firstToken, name_token);
3091 qualifyBlockTag (st, name_token);
3092 if (free_name_token)
3093 deleteToken (name_token);
3095 break;
3097 case TOKEN_ARRAY:
3098 case TOKEN_SEMICOLON:
3099 case TOKEN_COMMA:
3101 if (insideEnumBody (st) &&
3102 /* Java enumerations can contain members after a semicolon */
3103 (! isLanguage (Lang_java) || st->parent->nSemicolons < 2))
3105 else if (isType (prev, TOKEN_NAME))
3107 if (isContextualKeyword (prev2))
3108 makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
3109 else
3110 qualifyVariableTag (st, prev);
3112 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
3114 qualifyFunctionDeclTag (st, prev2);
3116 break;
3118 default:
3119 break;
3123 /* Parses the current file and decides whether to write out and tags that
3124 * are discovered.
3126 static void createTags (const unsigned int nestLevel,
3127 statementInfo *const parent)
3129 statementInfo *const st = newStatement (parent);
3131 DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
3132 while (TRUE)
3134 tokenInfo *token;
3136 nextToken (st);
3138 token = activeToken (st);
3140 if (isType (token, TOKEN_BRACE_CLOSE))
3142 if (nestLevel > 0)
3143 break;
3144 else
3146 verbose ("%s: unexpected closing brace at line %lu\n",
3147 getInputFileName (), getInputLineNumber ());
3148 longjmp (Exception, (int) ExceptionBraceFormattingError);
3151 else if (isType (token, TOKEN_DOUBLE_COLON))
3153 addContext (st, prevToken (st, 1));
3154 advanceToken (st);
3156 else
3158 tagCheck (st);/* this can add new token */
3159 if (isType (activeToken (st), TOKEN_BRACE_OPEN))
3160 nest (st, nestLevel + 1);
3161 checkStatementEnd (st);
3164 deleteStatement ();
3165 DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
3168 static boolean findCTags (const unsigned int passCount)
3170 exception_t exception;
3171 boolean retry;
3173 contextual_fake_count = 0;
3175 Assert (passCount < 3);
3176 cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp), isLanguage (Lang_cpp));
3178 exception = (exception_t) setjmp (Exception);
3179 retry = FALSE;
3181 if (exception == ExceptionNone)
3183 createTags (0, NULL);
3185 else
3187 deleteAllStatements ();
3188 if (exception == ExceptionBraceFormattingError && passCount == 1)
3190 retry = TRUE;
3191 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3192 getInputFileName ());
3195 cppTerminate ();
3196 return retry;
3199 static void buildKeywordHash (const langType language, unsigned int idx)
3201 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
3202 size_t i;
3203 for (i = 0 ; i < count ; ++i)
3205 const keywordDesc* const p = &KeywordTable [i];
3206 if (p->isValid [idx])
3207 addKeyword (p->name, language, (int) p->id);
3211 static void initializeCParser (const langType language)
3213 Lang_c = language;
3214 buildKeywordHash (language, 0);
3217 static void initializeCppParser (const langType language)
3219 Lang_cpp = language;
3220 buildKeywordHash (language, 1);
3223 static void initializeJavaParser (const langType language)
3225 Lang_java = language;
3226 buildKeywordHash (language, 3);
3229 static void initializeDParser (const langType language)
3231 /* treat these like const - some are for parsing like const(Type), some are just
3232 * function attributes */
3233 const char *const_aliases[] = {"immutable", "nothrow", "pure", "shared", NULL};
3234 const char **s;
3236 Lang_d = language;
3237 buildKeywordHash (language, 6);
3239 for (s = const_aliases; *s != NULL; s++)
3241 addKeyword (*s, language, KEYWORD_CONST);
3243 /* other keyword aliases */
3244 addKeyword ("alias", language, KEYWORD_TYPEDEF);
3245 /* skip 'static assert(...)' like 'static if (...)' */
3246 addKeyword ("assert", language, KEYWORD_IF);
3247 addKeyword ("unittest", language, KEYWORD_BODY); /* ignore */
3248 addKeyword ("version", language, KEYWORD_NAMESPACE); /* parse block */
3251 static void initializeGLSLParser (const langType language)
3253 Lang_glsl = language;
3254 buildKeywordHash (language, 0); /* C keywords */
3257 static void initializeFeriteParser (const langType language)
3259 Lang_ferite = language;
3260 buildKeywordHash (language, 1); /* C++ keywords */
3263 static void initializeCsharpParser (const langType language)
3265 Lang_csharp = language;
3266 buildKeywordHash (language, 2);
3269 static void initializeValaParser (const langType language)
3271 Lang_vala = language;
3272 buildKeywordHash (language, 5);
3274 /* keyword aliases */
3275 addKeyword ("ensures", language, KEYWORD_ATTRIBUTE); /* ignore */
3276 addKeyword ("errordomain", language, KEYWORD_ENUM); /* looks like enum */
3277 addKeyword ("requires", language, KEYWORD_ATTRIBUTE); /* ignore */
3280 extern parserDefinition* CParser (void)
3282 static const char *const extensions [] = { "c", "pc", "sc", NULL };
3283 parserDefinition* def = parserNew ("C");
3284 def->kinds = CKinds;
3285 def->kindCount = KIND_COUNT (CKinds);
3286 def->extensions = extensions;
3287 def->parser2 = findCTags;
3288 def->initialize = initializeCParser;
3289 return def;
3292 extern parserDefinition* CppParser (void)
3294 static const char *const extensions [] = {
3295 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3296 "i",
3297 #ifndef CASE_INSENSITIVE_FILENAMES
3298 "C", "H",
3299 #endif
3300 NULL
3302 parserDefinition* def = parserNew ("C++");
3303 def->kinds = CKinds;
3304 def->kindCount = KIND_COUNT (CKinds);
3305 def->extensions = extensions;
3306 def->parser2 = findCTags;
3307 def->initialize = initializeCppParser;
3308 return def;
3311 extern parserDefinition* JavaParser (void)
3313 static const char *const extensions [] = { "java", NULL };
3314 parserDefinition* def = parserNew ("Java");
3315 def->kinds = JavaKinds;
3316 def->kindCount = KIND_COUNT (JavaKinds);
3317 def->extensions = extensions;
3318 def->parser2 = findCTags;
3319 def->initialize = initializeJavaParser;
3320 return def;
3323 extern parserDefinition* DParser (void)
3325 static const char *const extensions [] = { "d", "di", NULL };
3326 parserDefinition* def = parserNew ("D");
3327 def->kinds = DKinds;
3328 def->kindCount = KIND_COUNT (DKinds);
3329 def->extensions = extensions;
3330 def->parser2 = findCTags;
3331 def->initialize = initializeDParser;
3332 return def;
3335 extern parserDefinition* GLSLParser (void)
3337 static const char *const extensions [] = { "glsl", "frag", "vert", NULL };
3338 parserDefinition* def = parserNew ("GLSL");
3339 def->kinds = CKinds;
3340 def->kindCount = KIND_COUNT (CKinds);
3341 def->extensions = extensions;
3342 def->parser2 = findCTags;
3343 def->initialize = initializeGLSLParser;
3344 return def;
3347 extern parserDefinition* FeriteParser (void)
3349 static const char *const extensions [] = { "fe", NULL };
3350 parserDefinition* def = parserNew ("Ferite");
3351 def->kinds = CKinds;
3352 def->kindCount = KIND_COUNT (CKinds);
3353 def->extensions = extensions;
3354 def->parser2 = findCTags;
3355 def->initialize = initializeFeriteParser;
3356 return def;
3359 extern parserDefinition* CsharpParser (void)
3361 static const char *const extensions [] = { "cs", NULL };
3362 parserDefinition* def = parserNew ("C#");
3363 def->kinds = CsharpKinds;
3364 def->kindCount = KIND_COUNT (CsharpKinds);
3365 def->extensions = extensions;
3366 def->parser2 = findCTags;
3367 def->initialize = initializeCsharpParser;
3368 return def;
3371 extern parserDefinition* ValaParser (void)
3373 static const char *const extensions [] = { "vala", NULL };
3374 parserDefinition* def = parserNew ("Vala");
3375 def->kinds = ValaKinds;
3376 def->kindCount = KIND_COUNT (ValaKinds);
3377 def->extensions = extensions;
3378 def->parser2 = findCTags;
3379 def->initialize = initializeValaParser;
3380 return def;
3382 /* vi:set tabstop=8 shiftwidth=4: */