Remove TagEntryFunction check in c.c
[geany-mirror.git] / ctags / parsers / c.c
blob03b45d96057f8d9c23b0efced54c8fc23f5c52d3
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 "lcpp.h"
23 #include "keyword.h"
24 #include "options.h"
25 #include "parse.h"
26 #include "read.h"
27 #include "routines.h"
28 #include "xtag.h"
31 * MACROS
34 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
35 #define parentDecl(st) ((st)->parent == NULL ? \
36 DECL_NONE : (st)->parent->declaration)
37 #define isType(token,t) (boolean) ((token)->type == (t))
38 #define insideEnumBody(st) (boolean) ((st)->parent == NULL ? FALSE : \
39 ((st)->parent->declaration == DECL_ENUM))
40 #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
41 ! (st)->haveQualifyingName && \
42 (st)->scope == SCOPE_EXTERN)
44 #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
47 * DATA DECLARATIONS
50 enum { NumTokens = 12 };
52 typedef enum eException
54 ExceptionNone, ExceptionEOF, ExceptionFormattingError,
55 ExceptionBraceFormattingError
56 } exception_t;
58 /* Used to specify type of keyword.
60 typedef enum eKeywordId
62 KEYWORD_NONE = -1,
63 KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT, KEYWORD_ALIAS,
64 KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
65 KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT, KEYWORD_BODY,
66 KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
67 KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
68 KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
69 KEYWORD_DOUBLE,
70 KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
71 KEYWORD_EXTENDS, KEYWORD_EVENT,
72 KEYWORD_FINAL, KEYWORD_FINALLY, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FRIEND, KEYWORD_FUNCTION,
73 KEYWORD_GET, KEYWORD_GOTO,
74 KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_IN, KEYWORD_INLINE, KEYWORD_INT,
75 KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
76 KEYWORD_INTERNAL,
77 KEYWORD_LOCAL, KEYWORD_LONG,
78 KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
79 KEYWORD_MODULE, KEYWORD_MUTABLE,
80 KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE, KEYWORD_NOEXCEPT,
81 KEYWORD_OPERATOR, KEYWORD_OUT, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
82 KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE,
83 KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
84 KEYWORD_REF, KEYWORD_REGISTER, KEYWORD_RETURN,
85 KEYWORD_SHADOW, KEYWORD_STATE,
86 KEYWORD_SET, KEYWORD_SHORT, KEYWORD_SIGNAL, KEYWORD_SIGNED, KEYWORD_SIZE_T, KEYWORD_STATIC,
87 KEYWORD_STATIC_ASSERT, KEYWORD_STRING,
88 KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
89 KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
90 KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
91 KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
92 KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
93 KEYWORD_USING,
94 KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
95 KEYWORD_WCHAR_T, KEYWORD_WEAK, KEYWORD_WHILE
96 } keywordId;
98 /* Used to determine whether keyword is valid for the current language and
99 * what its ID is.
101 typedef struct sKeywordDesc
103 const char *name;
104 keywordId id;
105 short isValid [7]; /* indicates languages for which kw is valid */
106 } keywordDesc;
108 /* Used for reporting the type of object parsed by nextToken ().
110 typedef enum eTokenType
112 TOKEN_NONE, /* none */
113 TOKEN_ARGS, /* a parenthetical pair and its contents */
114 TOKEN_BRACE_CLOSE,
115 TOKEN_BRACE_OPEN,
116 TOKEN_COMMA, /* the comma character */
117 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
118 TOKEN_KEYWORD,
119 TOKEN_NAME, /* an unknown name */
120 TOKEN_PACKAGE, /* a Java package name */
121 TOKEN_PAREN_NAME, /* a single name in parentheses */
122 TOKEN_SEMICOLON, /* the semicolon character */
123 TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
124 TOKEN_STAR, /* pointer detection */
125 TOKEN_ARRAY, /* array detection */
126 TOKEN_COUNT
127 } tokenType;
129 /* This describes the scoping of the current statement.
131 typedef enum eTagScope
133 SCOPE_GLOBAL, /* no storage class specified */
134 SCOPE_STATIC, /* static storage class */
135 SCOPE_EXTERN, /* external storage class */
136 SCOPE_FRIEND, /* declares access only */
137 SCOPE_TYPEDEF, /* scoping depends upon context */
138 SCOPE_COUNT
139 } tagScope;
141 typedef enum eDeclaration
143 DECL_NONE,
144 DECL_BASE, /* base type (default) */
145 DECL_CLASS,
146 DECL_ENUM,
147 DECL_EVENT,
148 DECL_SIGNAL,
149 DECL_FUNCTION,
150 DECL_FUNCTION_TEMPLATE,
151 DECL_IGNORE, /* non-taggable "declaration" */
152 DECL_INTERFACE,
153 DECL_MODULE,
154 DECL_NAMESPACE,
155 DECL_NOMANGLE, /* C++ name demangling block */
156 DECL_PACKAGE,
157 DECL_STRUCT,
158 DECL_UNION,
159 DECL_COUNT
160 } declType;
162 typedef enum eVisibilityType
164 ACCESS_UNDEFINED,
165 ACCESS_PRIVATE,
166 ACCESS_PROTECTED,
167 ACCESS_PUBLIC,
168 ACCESS_DEFAULT, /* Java-specific */
169 ACCESS_COUNT
170 } accessType;
172 /* Information about the parent class of a member (if any).
174 typedef struct sMemberInfo
176 accessType access; /* access of current statement */
177 accessType accessDefault; /* access default for current statement */
178 } memberInfo;
180 typedef struct sTokenInfo
182 tokenType type;
183 keywordId keyword;
184 vString* name; /* the name of the token */
185 unsigned long lineNumber; /* line number of tag */
186 MIOPos filePosition; /* file position of line containing name */
187 } tokenInfo;
189 typedef enum eImplementation
191 IMP_DEFAULT,
192 IMP_ABSTRACT,
193 IMP_VIRTUAL,
194 IMP_PURE_VIRTUAL,
195 IMP_COUNT
196 } impType;
198 /* Describes the statement currently undergoing analysis.
200 typedef struct sStatementInfo
202 tagScope scope;
203 declType declaration; /* specifier associated with TOKEN_SPEC */
204 boolean gotName; /* was a name parsed yet? */
205 boolean haveQualifyingName; /* do we have a name we are considering? */
206 boolean gotParenName; /* was a name inside parentheses parsed yet? */
207 boolean gotArgs; /* was a list of parameters parsed yet? */
208 unsigned int nSemicolons; /* how many semicolons did we see in that statement */
209 impType implementation; /* abstract or concrete implementation? */
210 unsigned int tokenIndex; /* currently active token */
211 tokenInfo* token [((int) NumTokens)];
212 tokenInfo* context; /* accumulated scope of current statement */
213 tokenInfo* blockName; /* name of current block */
214 memberInfo member; /* information regarding parent class/struct */
215 vString* parentClasses; /* parent classes */
216 struct sStatementInfo *parent; /* statement we are nested within */
217 long argEndPosition; /* Position where argument list ended */
218 tokenInfo* firstToken; /* First token in the statement */
219 } statementInfo;
221 /* Describes the type of tag being generated.
223 typedef enum eTagType
225 TAG_UNDEFINED,
226 TAG_CLASS, /* class name */
227 TAG_ENUM, /* enumeration name */
228 TAG_ENUMERATOR, /* enumerator (enumeration value) */
229 TAG_FIELD, /* field (Java) */
230 TAG_FUNCTION, /* function definition */
231 TAG_INTERFACE, /* interface declaration */
232 TAG_MEMBER, /* structure, class or interface member */
233 TAG_METHOD, /* method declaration */
234 TAG_NAMESPACE, /* namespace name */
235 TAG_PACKAGE, /* package name / D module name */
236 TAG_PROTOTYPE, /* function prototype or declaration */
237 TAG_STRUCT, /* structure name */
238 TAG_TYPEDEF, /* typedef name */
239 TAG_UNION, /* union name */
240 TAG_VARIABLE, /* variable definition */
241 TAG_EXTERN_VAR, /* external variable declaration */
242 TAG_MACRO, /* #define s */
243 TAG_EVENT, /* event */
244 TAG_SIGNAL, /* signal */
245 TAG_LOCAL, /* local variable definition */
246 TAG_PROPERTY, /* property name */
247 TAG_COUNT /* must be last */
248 } tagType;
250 typedef struct sParenInfo
252 boolean isParamList;
253 boolean isKnrParamList;
254 boolean isNameCandidate;
255 boolean invalidContents;
256 boolean nestedArgs;
257 unsigned int parameterCount;
258 } parenInfo;
261 * DATA DEFINITIONS
264 static jmp_buf Exception;
266 static langType Lang_c;
267 static langType Lang_cpp;
268 static langType Lang_csharp;
269 static langType Lang_java;
270 static langType Lang_d;
271 static langType Lang_glsl;
272 static langType Lang_ferite;
273 static langType Lang_vala;
275 /* Used to index into the CKinds table. */
276 typedef enum
278 CK_UNDEFINED = -1,
279 CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
280 CK_ENUMERATION, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
281 CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
282 CK_EXTERN_VARIABLE
283 } cKind;
285 static kindOption CKinds [] = {
286 { TRUE, 'c', "class", "classes"},
287 { TRUE, 'd', "macro", "macro definitions"},
288 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
289 { TRUE, 'f', "function", "function definitions"},
290 { TRUE, 'g', "enum", "enumeration names"},
291 { TRUE, 'm', "member", "class, struct, and union members"},
292 { TRUE, 'n', "namespace", "namespaces"},
293 { FALSE, 'p', "prototype", "function prototypes"},
294 { TRUE, 's', "struct", "structure names"},
295 { TRUE, 't', "typedef", "typedefs"},
296 { TRUE, 'u', "union", "union names"},
297 { TRUE, 'v', "variable", "variable definitions"},
298 { FALSE, 'x', "externvar", "external variable declarations"},
301 /* Used to index into the DKinds table. */
302 typedef enum
304 DK_UNDEFINED = -1,
305 DK_CLASS, DK_ENUMERATOR, DK_FUNCTION,
306 DK_ENUMERATION, DK_INTERFACE, DK_MEMBER, DK_NAMESPACE, DK_PROTOTYPE,
307 DK_STRUCT, DK_TYPEDEF, DK_UNION, DK_VARIABLE,
308 DK_EXTERN_VARIABLE
309 } dKind;
311 static kindOption DKinds [] = {
312 { TRUE, 'c', "class", "classes"},
313 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
314 { TRUE, 'f', "function", "function definitions"},
315 { TRUE, 'g', "enum", "enumeration names"},
316 { TRUE, 'i', "interface", "interfaces"},
317 { TRUE, 'm', "member", "class, struct, and union members"},
318 { TRUE, 'n', "namespace", "namespaces"},
319 { FALSE, 'p', "prototype", "function prototypes"},
320 { TRUE, 's', "struct", "structure names"},
321 { TRUE, 't', "typedef", "typedefs"},
322 { TRUE, 'u', "union", "union names"},
323 { TRUE, 'v', "variable", "variable definitions"},
324 { FALSE, 'x', "externvar", "external variable declarations"},
327 /* Used to index into the JavaKinds table. */
328 typedef enum
330 JK_UNDEFINED = -1,
331 JK_CLASS, JK_FIELD, JK_INTERFACE, JK_METHOD,
332 JK_PACKAGE, JK_ENUMERATOR, JK_ENUMERATION
333 } javaKind;
335 static kindOption JavaKinds [] = {
336 { TRUE, 'c', "class", "classes"},
337 { TRUE, 'f', "field", "fields"},
338 { TRUE, 'i', "interface", "interfaces"},
339 { TRUE, 'm', "method", "methods"},
340 { TRUE, 'p', "package", "packages"},
341 { TRUE, 'e', "enumConstant", "enum constants"},
342 { TRUE, 'g', "enum", "enum types"},
345 typedef enum
347 CSK_UNDEFINED = -1,
348 CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
349 CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
350 CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
351 } csharpKind;
353 static kindOption CsharpKinds [] = {
354 { TRUE, 'c', "class", "classes"},
355 { TRUE, 'd', "macro", "macro definitions"},
356 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
357 { TRUE, 'E', "event", "events"},
358 { TRUE, 'f', "field", "fields"},
359 { TRUE, 'g', "enum", "enumeration names"},
360 { TRUE, 'i', "interface", "interfaces"},
361 { FALSE, 'l', "local", "local variables"},
362 { TRUE, 'm', "method", "methods"},
363 { TRUE, 'n', "namespace", "namespaces"},
364 { TRUE, 'p', "property", "properties"},
365 { TRUE, 's', "struct", "structure names"},
366 { TRUE, 't', "typedef", "typedefs"},
369 typedef enum {
370 VK_UNDEFINED = -1,
371 VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FIELD,
372 VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_METHOD,
373 VK_NAMESPACE, VK_PROPERTY, VK_SIGNAL, VK_STRUCT
374 } valaKind;
376 static kindOption ValaKinds [] = {
377 { TRUE, 'c', "class", "classes"},
378 { TRUE, 'd', "macro", "macro definitions"},
379 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
380 { TRUE, 'f', "field", "fields"},
381 { TRUE, 'g', "enum", "enumeration names"},
382 { TRUE, 'i', "interface", "interfaces"},
383 { FALSE, 'l', "local", "local variables"},
384 { TRUE, 'm', "method", "methods"},
385 { TRUE, 'n', "namespace", "namespaces"},
386 { TRUE, 'p', "property", "properties"},
387 { TRUE, 'S', "signal", "signals"},
388 { TRUE, 's', "struct", "structure names"},
391 /* Note: some keyword aliases are added in initializeDParser, initializeValaParser */
392 static const keywordDesc KeywordTable [] = {
393 /* C++ */
394 /* ANSI C | C# Java */
395 /* | | | | Vera */
396 /* | | | | | Vala */
397 /* | | | | | | D */
398 /* keyword keyword ID | | | | | | | */
399 { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0, 0, 1 } },
400 { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0, 1, 1 } },
401 { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
402 { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
403 { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1, 0, 0 } },
404 { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1, 0, 0 } },
405 { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1, 0, 0 } },
406 { "body", KEYWORD_BODY, { 0, 0, 0, 0, 0, 0, 1 } },
407 { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0, 0, 0 } },
408 { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0, 0, 1 } },
409 { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0, 1, 1 } },
410 { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0, 1, 1 } },
411 { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0, 1, 1 } },
412 { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1, 1, 1 } },
413 { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0, 1, 1 } },
414 { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1, 0, 0 } },
415 { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1, 0, 0 } },
416 { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1, 0, 0 } },
417 { "do", KEYWORD_DO, { 1, 1, 1, 1, 0, 1, 1 } },
418 { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0, 1, 1 } },
419 { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0, 1, 1 } },
420 { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0, 1, 1 } },
421 { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0, 1, 1 } },
422 { "else", KEYWORD_ELSE, { 1, 1, 0, 1, 0, 1, 1 } },
423 { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1, 1, 1 } },
424 { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1, 0, 0 } },
425 { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0, 0, 1 } },
426 { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1, 0, 0 } },
427 { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1, 1, 0 } },
428 { "extern", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
429 { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0, 0, 1 } },
430 { "finally", KEYWORD_FINALLY, { 0, 0, 0, 0, 0, 1, 1 } },
431 { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0, 1, 1 } },
432 { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0, 1, 1 } },
433 { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0, 0, 0 } },
434 { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1, 0, 1 } },
435 { "get", KEYWORD_GET, { 0, 0, 0, 0, 0, 1, 0 } },
436 { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0, 1, 1 } },
437 { "if", KEYWORD_IF, { 1, 1, 1, 1, 0, 1, 1 } },
438 { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0, 0, 0 } },
439 { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0, 0, 1 } },
440 { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0, 1, 0 } },
441 { "in", KEYWORD_IN, { 0, 0, 0, 0, 0, 0, 1 } },
442 { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1, 0, 0 } },
443 { "inout", KEYWORD_CONST, { 0, 0, 0, 0, 0, 0, 1 } }, /* treat like const */
444 { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1, 0, 0 } },
445 { "int", KEYWORD_INT, { 1, 1, 1, 1, 0, 1, 1 } },
446 { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1, 0, 0 } },
447 { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1, 1, 1 } },
448 { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0, 0, 0 } },
449 { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1, 0, 0 } },
450 { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0, 1, 1 } },
451 { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
452 { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
453 { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
454 { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
455 { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0, 0, 0 } },
456 { "module", KEYWORD_MODULE, { 0, 0, 0, 0, 0, 0, 1 } },
457 { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0, 1, 0 } },
458 { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0, 0, 0 } },
459 { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0, 1, 1 } },
460 { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1, 0, 0 } },
461 { "noexcept", KEYWORD_NOEXCEPT, { 0, 1, 0, 0, 0, 0, 0 } },
462 { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0, 0, 0 } },
463 { "out", KEYWORD_OUT, { 0, 0, 0, 0, 0, 1, 1 } },
464 { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1, 0, 0 } },
465 { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0, 0, 0 } },
466 { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0, 1, 1 } },
467 { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0, 0, 1 } },
468 { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1, 0, 0 } },
469 { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1, 0, 0 } },
470 { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0, 1, 1 } },
471 { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1, 0, 0 } },
472 { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1, 1, 1 } },
473 { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1, 1, 1 } },
474 { "ref", KEYWORD_REF, { 0, 0, 0, 0, 0, 1, 1 } },
475 { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0, 0, 0 } },
476 { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0, 1, 1 } },
477 { "set", KEYWORD_SET, { 0, 0, 0, 0, 0, 1, 0 } },
478 { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1, 0, 0 } },
479 { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0, 1, 1 } },
480 { "signal", KEYWORD_SIGNAL, { 0, 0, 0, 0, 0, 1, 0 } },
481 { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0, 0, 0 } },
482 { "size_t", KEYWORD_SIZE_T, { 0, 0, 0, 0, 0, 1, 0 } },
483 { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
484 { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1, 1, 1 } },
485 { "static_assert", KEYWORD_STATIC_ASSERT, { 0, 1, 0, 0, 0, 0, 0 } },
486 { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1, 1, 0 } },
487 { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0, 1, 1 } },
488 { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0, 1, 1 } },
489 { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0, 0, 1 } },
490 { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1, 0, 0 } },
491 { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0, 0, 0 } },
492 { "template", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
493 { "this", KEYWORD_THIS, { 0, 0, 1, 1, 0, 1, 0 } }, /* 0 to allow D ctor tags */
494 { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0, 1, 1 } },
495 { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0, 1, 0 } },
496 { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
497 { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1, 0, 0 } },
498 { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0, 0, 0 } },
499 { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0, 1, 1 } },
500 { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1, 0, 1 } },
501 { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0, 0, 0 } },
502 { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0, 1, 1 } },
503 { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0, 1, 1 } },
504 { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0, 0, 1 } },
505 { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0, 0, 1 } },
506 { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0, 1, 1 } },
507 { "using", KEYWORD_USING, { 0, 1, 1, 0, 0, 1, 0 } },
508 { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1, 1, 0 } },
509 { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1, 1, 1 } },
510 { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0, 0, 1 } },
511 { "wchar_t", KEYWORD_WCHAR_T, { 0, 1, 1, 0, 0, 0, 0 } },
512 { "weak", KEYWORD_WEAK, { 0, 0, 0, 0, 0, 1, 0 } },
513 { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0, 1, 1 } }
518 * FUNCTION PROTOTYPES
520 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
521 static void copyToken (tokenInfo *const dest, const tokenInfo *const src);
522 static const char *getVarType (const statementInfo *const st,
523 const tokenInfo *const token);
526 * FUNCTION DEFINITIONS
529 /* Debugging functions added by Biswa */
530 #if defined(DEBUG_C) && DEBUG_C
531 static char *tokenTypeName[] = {
532 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
533 "package", "paren-name", "';'", "spec", "*", "[]", "count"
536 static char *tagScopeNames[] = {
537 "global", "static", "extern", "friend", "typedef", "count"};
539 static char *declTypeNames[] = {
540 "none", "base", "class", "enum", "function", "ignore", "interface",
541 "namespace", "nomangle", "package", "struct", "union", "count"};
543 static char *impTypeNames[] = {
544 "default", "abstract", "virtual", "pure-virtual", "count"};
546 void printToken(const tokenInfo *const token)
548 fprintf(stderr, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName[token->type],
549 token->keyword, vStringValue(token->name));
552 void printTagEntry(const tagEntryInfo *tag)
554 fprintf(stderr, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag->name,
555 tag->kindName, tag->extensionFields.implementation, tag->extensionFields.scope[1],
556 tag->extensionFields.varType);
559 void printStatement(const statementInfo *const statement)
561 int i;
562 statementInfo *st = (statementInfo *) statement;
563 while (NULL != st)
565 fprintf(stderr, "Statement Info:\n------------------------\n");
566 fprintf(stderr, "scope: %s, decl: %s, impl: %s\n", tagScopeNames[st->scope],
567 declTypeNames[st->declaration], impTypeNames[st->implementation]);
568 for (i=0; i < NumTokens; ++i)
570 fprintf(stderr, "Token %d %s: ", i, (i == st->tokenIndex)?"(current)":"");
571 printToken(st->token[i]);
573 fprintf(stderr, "Context: ");
574 printToken(st->context);
575 fprintf(stderr, "Block: ");
576 printToken(st->blockName);
577 fprintf(stderr, "Parent classes: %s\n", vStringValue(st->parentClasses));
578 fprintf(stderr, "First token: ");
579 printToken(st->firstToken);
580 if (NULL != st->parent)
581 fprintf(stderr, "Printing Parent:\n");
582 st = st->parent;
584 fprintf(stderr, "-----------------------------------------------\n");
586 #endif
588 extern boolean includingDefineTags (void)
590 if (isInputLanguage(Lang_c) ||
591 isInputLanguage(Lang_cpp) ||
592 isInputLanguage(Lang_csharp) ||
593 isInputLanguage(Lang_ferite) ||
594 isInputLanguage(Lang_glsl) ||
595 isInputLanguage(Lang_vala))
596 return CKinds [CK_DEFINE].enabled;
598 return FALSE;
602 * Token management
605 static void initToken (tokenInfo* const token)
607 token->type = TOKEN_NONE;
608 token->keyword = KEYWORD_NONE;
609 token->lineNumber = getInputLineNumber ();
610 token->filePosition = getInputFilePosition ();
611 vStringClear (token->name);
614 static void advanceToken (statementInfo* const st)
616 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
617 st->tokenIndex = 0;
618 else
619 ++st->tokenIndex;
620 initToken (st->token [st->tokenIndex]);
623 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
625 unsigned int tokenIndex;
626 unsigned int num = (unsigned int) NumTokens;
627 Assert (n < num);
628 tokenIndex = (st->tokenIndex + num - n) % num;
629 return st->token [tokenIndex];
632 static void setToken (statementInfo *const st, const tokenType type)
634 tokenInfo *token;
635 token = activeToken (st);
636 initToken (token);
637 token->type = type;
640 static void retardToken (statementInfo *const st)
642 if (st->tokenIndex == 0)
643 st->tokenIndex = (unsigned int) NumTokens - 1;
644 else
645 --st->tokenIndex;
646 setToken (st, TOKEN_NONE);
649 static tokenInfo *newToken (void)
651 tokenInfo *const token = xMalloc (1, tokenInfo);
652 token->name = vStringNew ();
653 initToken (token);
654 return token;
657 static void deleteToken (tokenInfo *const token)
659 if (token != NULL)
661 vStringDelete (token->name);
662 eFree (token);
666 static const char *accessString (const accessType laccess)
668 static const char *const names [] = {
669 "?", "private", "protected", "public", "default"
671 Assert (ARRAY_SIZE (names) == ACCESS_COUNT);
672 Assert ((int) laccess < ACCESS_COUNT);
673 return names[(int) laccess];
676 static const char *implementationString (const impType imp)
678 static const char *const names [] = {
679 "?", "abstract", "virtual", "pure virtual"
681 Assert (ARRAY_SIZE (names) == IMP_COUNT);
682 Assert ((int) imp < IMP_COUNT);
683 return names [(int) imp];
687 * Debugging functions
690 #ifdef DEBUG
692 #define boolString(c) ((c) ? "TRUE" : "FALSE")
694 static const char *tokenString (const tokenType type)
696 static const char *const names [] = {
697 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
698 "package", "paren-name", "semicolon", "specifier", "*", "[]"
700 Assert (ARRAY_SIZE (names) == TOKEN_COUNT);
701 Assert ((int) type < TOKEN_COUNT);
702 return names [(int) type];
705 static const char *scopeString (const tagScope scope)
707 static const char *const names [] = {
708 "global", "static", "extern", "friend", "typedef"
710 Assert (ARRAY_SIZE (names) == SCOPE_COUNT);
711 Assert ((int) scope < SCOPE_COUNT);
712 return names [(int) scope];
715 static const char *declString (const declType declaration)
717 static const char *const names [] = {
718 "?", "base", "class", "enum", "event", "signal", "function",
719 "function template", "ignore", "interface", "module", "namespace",
720 "no mangle", "package", "struct", "union",
722 Assert (ARRAY_SIZE (names) == DECL_COUNT);
723 Assert ((int) declaration < DECL_COUNT);
724 return names [(int) declaration];
727 static const char *keywordString (const keywordId keyword)
729 const size_t count = ARRAY_SIZE (KeywordTable);
730 const char *name = "none";
731 size_t i;
732 for (i = 0 ; i < count ; ++i)
734 const keywordDesc *p = &KeywordTable [i];
735 if (p->id == keyword)
737 name = p->name;
738 break;
741 return name;
744 static void UNUSED pt (tokenInfo *const token)
746 if (isType (token, TOKEN_NAME))
747 printf ("type: %-12s: %-13s line: %lu\n",
748 tokenString (token->type), vStringValue (token->name),
749 token->lineNumber);
750 else if (isType (token, TOKEN_KEYWORD))
751 printf ("type: %-12s: %-13s line: %lu\n",
752 tokenString (token->type), keywordString (token->keyword),
753 token->lineNumber);
754 else
755 printf ("type: %-12s line: %lu\n",
756 tokenString (token->type), token->lineNumber);
759 static void UNUSED ps (statementInfo *const st)
761 unsigned int i;
762 printf("scope: %s decl: %s gotName: %s gotParenName: %s\n",
763 scopeString (st->scope), declString (st->declaration),
764 boolString (st->gotName), boolString (st->gotParenName));
765 printf("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
766 printf("access: %s default: %s\n", accessString (st->member.access),
767 accessString (st->member.accessDefault));
768 printf("token : ");
769 pt(activeToken (st));
770 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
772 printf("prev %u : ", i);
773 pt(prevToken (st, i));
775 printf("context: ");
776 pt(st->context);
779 #endif
782 * Statement management
785 static boolean isDataTypeKeyword (const tokenInfo *const token)
787 switch (token->keyword)
789 case KEYWORD_BOOLEAN:
790 case KEYWORD_BYTE:
791 case KEYWORD_CHAR:
792 case KEYWORD_DOUBLE:
793 case KEYWORD_FLOAT:
794 case KEYWORD_INT:
795 case KEYWORD_LONG:
796 case KEYWORD_SHORT:
797 case KEYWORD_VOID:
798 case KEYWORD_WCHAR_T:
799 case KEYWORD_SIZE_T:
800 return TRUE;
801 default:
802 return FALSE;
806 #if 0
807 static boolean isVariableKeyword (const tokenInfo *const token)
809 switch (token->keyword)
811 case KEYWORD_CONST:
812 case KEYWORD_EXTERN:
813 case KEYWORD_REGISTER:
814 case KEYWORD_STATIC:
815 case KEYWORD_VIRTUAL:
816 case KEYWORD_SIGNED:
817 case KEYWORD_UNSIGNED:
818 return TRUE;
819 default:
820 return FALSE;
823 #endif
825 static boolean isContextualKeyword (const tokenInfo *const token)
827 boolean result;
828 switch (token->keyword)
830 case KEYWORD_CLASS:
831 case KEYWORD_ENUM:
832 case KEYWORD_INTERFACE:
833 case KEYWORD_NAMESPACE:
834 case KEYWORD_STRUCT:
835 case KEYWORD_UNION:
837 result = TRUE;
838 break;
841 default:
843 result = FALSE;
844 break;
847 return result;
850 static boolean isContextualStatement (const statementInfo *const st)
852 boolean result = FALSE;
854 if (st != NULL)
856 if (isInputLanguage (Lang_vala))
858 /* All can be a contextual statement as properties can be of any type */
859 result = TRUE;
861 else
863 switch (st->declaration)
865 case DECL_CLASS:
866 case DECL_ENUM:
867 case DECL_INTERFACE:
868 case DECL_NAMESPACE:
869 case DECL_STRUCT:
870 case DECL_UNION:
872 result = TRUE;
873 break;
876 default:
878 result = FALSE;
879 break;
884 return result;
887 static boolean isMember (const statementInfo *const st)
889 boolean result;
890 if (isType (st->context, TOKEN_NAME))
891 result = TRUE;
892 else
893 result = isContextualStatement (st->parent);
894 return result;
897 static void initMemberInfo (statementInfo *const st)
899 accessType accessDefault = ACCESS_UNDEFINED;
901 if (st->parent != NULL) switch (st->parent->declaration)
903 case DECL_ENUM:
904 case DECL_NAMESPACE:
906 accessDefault = ACCESS_UNDEFINED;
907 break;
909 case DECL_CLASS:
911 if (isInputLanguage (Lang_java))
912 accessDefault = ACCESS_DEFAULT;
913 else
914 accessDefault = ACCESS_PRIVATE;
915 break;
917 case DECL_INTERFACE:
918 case DECL_STRUCT:
919 case DECL_UNION:
921 accessDefault = ACCESS_PUBLIC;
922 break;
924 default:
925 break;
927 st->member.accessDefault = accessDefault;
928 st->member.access = accessDefault;
931 static void reinitStatement (statementInfo *const st, const boolean partial)
933 unsigned int i;
935 if (! partial)
937 st->scope = SCOPE_GLOBAL;
938 if (isContextualStatement (st->parent))
939 st->declaration = DECL_BASE;
940 else
941 st->declaration = DECL_NONE;
943 st->gotParenName = FALSE;
944 st->implementation = IMP_DEFAULT;
945 st->gotArgs = FALSE;
946 st->gotName = FALSE;
947 st->nSemicolons = 0;
948 st->haveQualifyingName = FALSE;
949 st->argEndPosition = 0;
951 st->tokenIndex = 0;
952 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
954 initToken (st->token [i]);
957 initToken (st->context);
958 initToken (st->blockName);
959 vStringClear (st->parentClasses);
961 /* Init member info. */
962 if (! partial)
963 st->member.access = st->member.accessDefault;
965 /* Init first token */
966 if (!partial)
967 initToken(st->firstToken);
970 static void reinitStatementWithToken (statementInfo *const st,
971 tokenInfo *token, const boolean partial)
973 tokenInfo *const save = newToken ();
974 /* given token can be part of reinit statementInfo */
975 copyToken (save, token);
976 reinitStatement (st, partial);
977 token = activeToken (st);
978 copyToken (token, save);
979 deleteToken (save);
980 ++st->tokenIndex; /* this is quite safe because current tokenIndex = 0 */
983 static void initStatement (statementInfo *const st, statementInfo *const parent)
985 st->parent = parent;
986 initMemberInfo (st);
987 reinitStatement (st, FALSE);
988 if (parent)
990 const tokenInfo *const src = activeToken (parent);
991 tokenInfo *const dst = activeToken (st);
992 copyToken (dst, src);
993 st->tokenIndex++;
998 * Tag generation functions
1000 static cKind cTagKind (const tagType type)
1002 cKind result = CK_UNDEFINED;
1003 switch (type)
1005 case TAG_CLASS: result = CK_CLASS; break;
1006 case TAG_ENUM: result = CK_ENUMERATION; break;
1007 case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
1008 case TAG_FUNCTION: result = CK_FUNCTION; break;
1009 case TAG_MEMBER: result = CK_MEMBER; break;
1010 case TAG_NAMESPACE: result = CK_NAMESPACE; break;
1011 case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
1012 case TAG_STRUCT: result = CK_STRUCT; break;
1013 case TAG_TYPEDEF: result = CK_TYPEDEF; break;
1014 case TAG_UNION: result = CK_UNION; break;
1015 case TAG_VARIABLE: result = CK_VARIABLE; break;
1016 case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
1018 default: Assert ("Bad C tag type" == NULL); break;
1020 return result;
1023 static csharpKind csharpTagKind (const tagType type)
1025 csharpKind result = CSK_UNDEFINED;
1026 switch (type)
1028 case TAG_CLASS: result = CSK_CLASS; break;
1029 case TAG_ENUM: result = CSK_ENUMERATION; break;
1030 case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
1031 case TAG_EVENT: result = CSK_EVENT; break;
1032 case TAG_FIELD: result = CSK_FIELD ; break;
1033 case TAG_INTERFACE: result = CSK_INTERFACE; break;
1034 case TAG_LOCAL: result = CSK_LOCAL; break;
1035 case TAG_METHOD: result = CSK_METHOD; break;
1036 case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
1037 case TAG_PROPERTY: result = CSK_PROPERTY; break;
1038 case TAG_STRUCT: result = CSK_STRUCT; break;
1039 case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
1041 default: Assert ("Bad C# tag type" == NULL); break;
1043 return result;
1046 static dKind dTagKind (const tagType type)
1048 dKind result = DK_UNDEFINED;
1049 switch (type)
1051 case TAG_CLASS: result = DK_CLASS; break;
1052 case TAG_ENUM: result = DK_ENUMERATION; break;
1053 case TAG_ENUMERATOR: result = DK_ENUMERATOR; break;
1054 case TAG_FUNCTION: result = DK_FUNCTION; break;
1055 case TAG_INTERFACE: result = DK_INTERFACE; break;
1056 case TAG_MEMBER: result = DK_MEMBER; break;
1057 case TAG_NAMESPACE: result = DK_NAMESPACE; break;
1058 case TAG_PROTOTYPE: result = DK_PROTOTYPE; break;
1059 case TAG_STRUCT: result = DK_STRUCT; break;
1060 case TAG_TYPEDEF: result = DK_TYPEDEF; break;
1061 case TAG_UNION: result = DK_UNION; break;
1062 case TAG_VARIABLE: result = DK_VARIABLE; break;
1063 case TAG_EXTERN_VAR: result = DK_EXTERN_VARIABLE; break;
1065 default: Assert ("Bad D tag type" == NULL); break;
1067 return result;
1070 static valaKind valaTagKind (const tagType type)
1072 valaKind result = VK_UNDEFINED;
1073 switch (type)
1075 case TAG_CLASS: result = VK_CLASS; break;
1076 case TAG_ENUM: result = VK_ENUMERATION; break;
1077 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
1078 case TAG_SIGNAL: result = VK_SIGNAL; break;
1079 case TAG_FIELD: result = VK_FIELD ; break;
1080 case TAG_INTERFACE: result = VK_INTERFACE; break;
1081 case TAG_LOCAL: result = VK_LOCAL; break;
1082 case TAG_METHOD: result = VK_METHOD; break;
1083 case TAG_NAMESPACE: result = VK_NAMESPACE; break;
1084 case TAG_PROPERTY: result = VK_PROPERTY; break;
1085 case TAG_STRUCT: result = VK_STRUCT; break;
1087 default: Assert ("Bad Vala tag type" == NULL); break;
1089 return result;
1092 static javaKind javaTagKind (const tagType type)
1094 javaKind result = JK_UNDEFINED;
1095 switch (type)
1097 case TAG_CLASS: result = JK_CLASS; break;
1098 case TAG_FIELD: result = JK_FIELD; break;
1099 case TAG_INTERFACE: result = JK_INTERFACE; break;
1100 case TAG_METHOD: result = JK_METHOD; break;
1101 case TAG_PACKAGE: result = JK_PACKAGE; break;
1102 case TAG_ENUM: result = JK_ENUMERATION; break;
1103 case TAG_ENUMERATOR: result = JK_ENUMERATOR; break;
1105 default: Assert ("Bad Java tag type" == NULL); break;
1107 return result;
1110 static const kindOption *tagKind (const tagType type)
1112 const kindOption* result;
1113 if (isInputLanguage (Lang_java))
1114 result = &JavaKinds [javaTagKind (type)];
1115 else if (isInputLanguage (Lang_csharp))
1116 result = &CsharpKinds [csharpTagKind (type)];
1117 else if (isInputLanguage (Lang_d))
1118 result = &DKinds [dTagKind (type)];
1119 else if (isInputLanguage (Lang_vala))
1120 result = &ValaKinds [valaTagKind (type)];
1121 else
1122 result = &CKinds [cTagKind (type)];
1123 return result;
1127 static boolean includeTag (const tagType type, const boolean isFileScope)
1129 boolean result;
1130 if (isFileScope && ! Option.include.fileScope)
1131 result = FALSE;
1132 else if (isInputLanguage (Lang_java))
1133 result = JavaKinds [javaTagKind (type)].enabled;
1134 else
1135 result = CKinds [cTagKind (type)].enabled;
1136 return result;
1140 static tagType declToTagType (const declType declaration)
1142 tagType type = TAG_UNDEFINED;
1144 switch (declaration)
1146 case DECL_CLASS: type = TAG_CLASS; break;
1147 case DECL_ENUM: type = TAG_ENUM; break;
1148 case DECL_FUNCTION: type = TAG_FUNCTION; break;
1149 case DECL_FUNCTION_TEMPLATE: type = TAG_FUNCTION; break;
1150 case DECL_INTERFACE: type = TAG_INTERFACE; break;
1151 case DECL_NAMESPACE: type = TAG_NAMESPACE; break;
1152 case DECL_STRUCT: type = TAG_STRUCT; break;
1153 case DECL_UNION: type = TAG_UNION; break;
1155 default: Assert ("Unexpected declaration" == NULL); break;
1157 return type;
1160 static const char* accessField (const statementInfo *const st)
1162 const char* result = NULL;
1164 if ((isInputLanguage (Lang_cpp) || isInputLanguage (Lang_d) || isInputLanguage (Lang_ferite)) &&
1165 st->scope == SCOPE_FRIEND)
1166 result = "friend";
1167 else if (st->member.access != ACCESS_UNDEFINED)
1168 result = accessString (st->member.access);
1169 return result;
1172 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
1173 const tokenInfo *const nameToken,
1174 const statementInfo *const st, vString *const scope)
1176 /* For selected tag types, append an extension flag designating the
1177 * parent object in which the tag is defined.
1179 switch (type)
1181 default: break;
1183 case TAG_NAMESPACE:
1184 case TAG_CLASS:
1185 case TAG_ENUM:
1186 case TAG_ENUMERATOR:
1187 case TAG_FIELD:
1188 case TAG_FUNCTION:
1189 case TAG_INTERFACE:
1190 case TAG_MEMBER:
1191 case TAG_METHOD:
1192 case TAG_PROTOTYPE:
1193 case TAG_STRUCT:
1194 case TAG_TYPEDEF:
1195 case TAG_UNION:
1197 if (vStringLength (scope) > 0 &&
1198 (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1200 if (isType (st->context, TOKEN_NAME))
1201 tag->extensionFields.scopeKind = tagKind (TAG_CLASS);
1202 else
1203 tag->extensionFields.scopeKind =
1204 tagKind (declToTagType (parentDecl (st)));
1205 tag->extensionFields.scopeName = vStringValue (scope);
1207 if ((type == TAG_CLASS || type == TAG_INTERFACE ||
1208 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
1210 tag->extensionFields.inheritance =
1211 vStringValue (st->parentClasses);
1213 if (st->implementation != IMP_DEFAULT &&
1214 (isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala) ||
1215 isInputLanguage (Lang_java) || isInputLanguage (Lang_d) || isInputLanguage (Lang_ferite)))
1217 tag->extensionFields.implementation =
1218 implementationString (st->implementation);
1220 if (isMember (st))
1222 tag->extensionFields.access = accessField (st);
1224 if ((TRUE == st->gotArgs) && (TRUE == Option.extensionFields.argList) &&
1225 ((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type)))
1227 tag->extensionFields.signature = cppGetArglistFromFilePos(
1228 tag->filePosition, tag->name);
1230 break;
1234 if ((TAG_FIELD == type) || (TAG_MEMBER == type) ||
1235 (TAG_EXTERN_VAR == type) || (TAG_TYPEDEF == type) ||
1236 (TAG_VARIABLE == type) || (TAG_METHOD == type) ||
1237 (TAG_PROTOTYPE == type) || (TAG_FUNCTION == type))
1239 if (((TOKEN_NAME == st->firstToken->type) || isDataTypeKeyword(st->firstToken))
1240 && (0 != strcmp(vStringValue(st->firstToken->name), tag->name)))
1242 tag->extensionFields.varType = getVarType(st, nameToken);
1247 static const char *getVarType (const statementInfo *const st,
1248 const tokenInfo *const nameToken)
1250 static vString *vt = NULL;
1251 unsigned int i;
1252 unsigned int end = st->tokenIndex;
1253 boolean seenType = FALSE;
1255 switch (st->declaration) {
1256 case DECL_BASE:
1257 case DECL_FUNCTION:
1258 case DECL_FUNCTION_TEMPLATE:
1259 break;
1260 default:
1261 return vStringValue(st->firstToken->name);
1264 if (vt == NULL)
1265 vt = vStringNew();
1266 else
1267 vStringClear(vt);
1269 /* find the end of the type signature in the token list */
1270 for (i = 0; i < st->tokenIndex; i++)
1272 const tokenInfo *const t = st->token[i];
1274 /* stop if we find the token used to generate the tag name, or
1275 * a name token in the middle yet not preceded by a scope separator */
1276 if ((t == nameToken ||
1277 (t->type == nameToken->type &&
1278 t->keyword == nameToken->keyword &&
1279 t->lineNumber == nameToken->lineNumber &&
1280 strcmp(vStringValue(t->name), vStringValue(nameToken->name)) == 0)) ||
1281 (t->type == TOKEN_NAME && seenType &&
1282 (i > 0 && st->token[i - 1]->type != TOKEN_DOUBLE_COLON)))
1284 break;
1286 if (t->type != TOKEN_DOUBLE_COLON)
1287 end = i + 1;
1288 if (t->type == TOKEN_NAME)
1289 seenType = TRUE;
1290 else if (t->type == TOKEN_KEYWORD && isDataTypeKeyword(t))
1291 seenType = TRUE;
1294 /* ugly historic workaround when we can't figure out the type */
1295 if (end < 2 && ! st->gotArgs)
1296 return vStringValue(st->firstToken->name);
1298 for (i = 0; i < end; i++)
1300 tokenInfo *t = st->token[i];
1302 switch (t->type)
1304 case TOKEN_NAME: /* user typename */
1305 break;
1306 case TOKEN_KEYWORD:
1307 if ((t->keyword != KEYWORD_EXTERN && t->keyword != KEYWORD_STATIC) && /* uninteresting keywords */
1308 (st->gotArgs ||
1309 /* ignore uninteresting keywords for non-functions */
1310 (t->keyword != KEYWORD_PUBLIC &&
1311 t->keyword != KEYWORD_PRIVATE &&
1312 t->keyword != KEYWORD_PROTECTED &&
1313 t->keyword != KEYWORD_FINAL &&
1314 t->keyword != KEYWORD_TYPEDEF &&
1315 /* hack for D static conditions */
1316 t->keyword != KEYWORD_IF)))
1318 break;
1320 continue;
1321 case TOKEN_STAR: vStringCatS(vt, " *"); continue;
1322 case TOKEN_ARRAY: vStringCatS(vt, "[]"); continue;
1323 case TOKEN_DOUBLE_COLON:
1324 vStringCatS(vt, "::");
1325 continue;
1326 default: continue;
1328 if (vStringLength(vt) > 0)
1329 if (isalpha(vStringValue(vt)[vStringLength(vt) - 1]))
1330 vStringPut(vt, ' ');
1331 vStringCat(vt, t->name);
1333 vStringTerminate(vt);
1334 return vStringValue(vt);
1337 static void addContextSeparator (vString *const scope)
1339 if (isInputLanguage (Lang_c) || isInputLanguage (Lang_cpp))
1340 vStringCatS (scope, "::");
1341 else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_d) || isInputLanguage (Lang_ferite) ||
1342 isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1343 vStringCatS (scope, ".");
1346 static void findScopeHierarchy (vString *const string,
1347 const statementInfo *const st)
1349 const char* const anon = "<anonymous>";
1350 boolean nonAnonPresent = FALSE;
1352 vStringClear (string);
1353 if (isType (st->context, TOKEN_NAME))
1355 vStringCopy (string, st->context->name);
1356 nonAnonPresent = TRUE;
1358 if (st->parent != NULL)
1360 vString *temp = vStringNew ();
1361 const statementInfo *s;
1363 for (s = st->parent ; s != NULL ; s = s->parent)
1365 if (isContextualStatement (s) ||
1366 s->declaration == DECL_NAMESPACE)
1368 vStringCopy (temp, string);
1369 vStringClear (string);
1370 if (isType (s->blockName, TOKEN_NAME))
1372 if (isType (s->context, TOKEN_NAME) &&
1373 vStringLength (s->context->name) > 0)
1375 vStringCat (string, s->context->name);
1376 addContextSeparator (string);
1378 vStringCat (string, s->blockName->name);
1379 nonAnonPresent = TRUE;
1381 else
1382 vStringCopyS (string, anon);
1383 if (vStringLength (temp) > 0)
1384 addContextSeparator (string);
1385 vStringCat (string, temp);
1388 vStringDelete (temp);
1390 if (! nonAnonPresent)
1391 vStringClear (string);
1395 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1396 vString *const scope)
1398 if (isXtagEnabled(XTAG_QUALIFIED_TAGS) &&
1399 scope != NULL && vStringLength (scope) > 0)
1401 vString *const scopedName = vStringNew ();
1403 if (type != TAG_ENUMERATOR)
1404 vStringCopy (scopedName, scope);
1405 else
1407 /* remove last component (i.e. enumeration name) from scope */
1408 const char* const sc = vStringValue (scope);
1409 const char* colon = strrchr (sc, ':');
1410 if (colon != NULL)
1412 while (*colon == ':' && colon > sc)
1413 --colon;
1414 vStringNCopy (scopedName, scope, colon + 1 - sc);
1417 if (vStringLength (scopedName) > 0)
1419 addContextSeparator (scopedName);
1420 vStringCatS (scopedName, e->name);
1421 e->name = vStringValue (scopedName);
1422 makeTagEntry (e);
1424 vStringDelete (scopedName);
1428 static void makeTag (const tokenInfo *const token,
1429 const statementInfo *const st,
1430 boolean isFileScope, const tagType type)
1432 #ifdef DEBUG_C
1433 printToken(token);
1434 fprintf(stderr, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
1435 printStatement(st);
1436 #endif
1437 /* Nothing is really of file scope when it appears in a header file.
1439 isFileScope = (boolean) (isFileScope && ! isInputHeaderFile ());
1441 if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 /* &&
1442 includeTag (type, isFileScope) */)
1444 vString *scope = vStringNew ();
1445 tagEntryInfo e;
1447 /* take only functions which are introduced by "function ..." */
1448 if (type == TAG_FUNCTION && isInputLanguage (Lang_ferite) &&
1449 strncmp("function", st->firstToken->name->buffer, 8) != 0)
1451 return;
1454 initTagEntry (&e, vStringValue (token->name), tagKind (type));
1456 e.lineNumber = token->lineNumber;
1457 e.filePosition = token->filePosition;
1458 e.isFileScope = isFileScope;
1460 findScopeHierarchy (scope, st);
1461 addOtherFields (&e, type, token, st, scope);
1463 #ifdef DEBUG_C
1464 printTagEntry(&e);
1465 #endif
1466 makeTagEntry (&e);
1467 makeExtraTagEntry (type, &e, scope);
1468 vStringDelete (scope);
1469 if (NULL != e.extensionFields.signature)
1470 free((char *) e.extensionFields.signature);
1474 static boolean isValidTypeSpecifier (const declType declaration)
1476 boolean result;
1477 switch (declaration)
1479 case DECL_BASE:
1480 case DECL_CLASS:
1481 case DECL_ENUM:
1482 case DECL_STRUCT:
1483 case DECL_UNION:
1484 result = TRUE;
1485 break;
1487 default:
1488 result = FALSE;
1489 break;
1491 return result;
1494 static void qualifyEnumeratorTag (const statementInfo *const st,
1495 const tokenInfo *const nameToken)
1497 if (isType (nameToken, TOKEN_NAME))
1498 makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
1501 static void qualifyFunctionTag (const statementInfo *const st,
1502 const tokenInfo *const nameToken)
1504 if (isType (nameToken, TOKEN_NAME))
1506 const tagType type = (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1507 ? TAG_METHOD : TAG_FUNCTION;
1508 const boolean isFileScope =
1509 (boolean) (st->member.access == ACCESS_PRIVATE ||
1510 (!isMember (st) && st->scope == SCOPE_STATIC));
1512 makeTag (nameToken, st, isFileScope, type);
1516 static void qualifyFunctionDeclTag (const statementInfo *const st,
1517 const tokenInfo *const nameToken)
1519 if (! isType (nameToken, TOKEN_NAME))
1521 else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1522 qualifyFunctionTag (st, nameToken);
1523 else if (st->scope == SCOPE_TYPEDEF)
1524 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1525 else if (isValidTypeSpecifier (st->declaration) &&
1526 ! (isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala)))
1527 makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
1530 static void qualifyCompoundTag (const statementInfo *const st,
1531 const tokenInfo *const nameToken)
1533 if (isType (nameToken, TOKEN_NAME))
1535 const tagType type = declToTagType (st->declaration);
1537 if (type != TAG_UNDEFINED)
1538 makeTag (nameToken, st, (boolean) (! isInputLanguage (Lang_java) &&
1539 ! isInputLanguage (Lang_csharp) &&
1540 ! isInputLanguage (Lang_vala)), type);
1544 static void qualifyBlockTag (statementInfo *const st,
1545 const tokenInfo *const nameToken)
1547 switch (st->declaration)
1549 case DECL_CLASS:
1550 case DECL_ENUM:
1551 case DECL_INTERFACE:
1552 case DECL_NAMESPACE:
1553 case DECL_STRUCT:
1554 case DECL_UNION:
1555 qualifyCompoundTag (st, nameToken);
1556 break;
1557 default: break;
1561 static void qualifyVariableTag (const statementInfo *const st,
1562 const tokenInfo *const nameToken)
1564 /* We have to watch that we do not interpret a declaration of the
1565 * form "struct tag;" as a variable definition. In such a case, the
1566 * token preceding the name will be a keyword.
1568 if (! isType (nameToken, TOKEN_NAME))
1570 else if (st->declaration == DECL_IGNORE)
1572 else if (st->scope == SCOPE_TYPEDEF)
1573 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1574 else if (st->declaration == DECL_PACKAGE)
1575 makeTag (nameToken, st, FALSE, TAG_PACKAGE);
1576 else if (st->declaration == DECL_MODULE) /* handle modules in D as namespaces */
1577 makeTag (nameToken, st, FALSE, TAG_NAMESPACE);
1578 else if (isValidTypeSpecifier (st->declaration))
1580 if (isMember (st))
1582 if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1583 makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1584 else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1585 makeTag (nameToken, st, TRUE, TAG_MEMBER);
1587 else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1589 else
1591 if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1592 makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
1593 else
1594 makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC), TAG_VARIABLE);
1600 * Parsing functions
1603 static int skipToOneOf (const char *const chars)
1605 int c;
1607 c = cppGetc ();
1608 while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1610 return c;
1613 /* Skip to the next non-white character.
1615 static int skipToNonWhite (void)
1617 int c;
1621 c = cppGetc ();
1623 while (isspace (c));
1625 return c;
1628 /* Skips to the next brace in column 1. This is intended for cases where
1629 * preprocessor constructs result in unbalanced braces.
1631 static void skipToFormattedBraceMatch (void)
1633 int c, next;
1635 c = cppGetc ();
1636 next = cppGetc ();
1637 while (c != EOF && (c != '\n' || next != '}'))
1639 c = next;
1640 next = cppGetc ();
1644 /* Skip to the matching character indicated by the pair string. If skipping
1645 * to a matching brace and any brace is found within a different level of a
1646 * #if conditional statement while brace formatting is in effect, we skip to
1647 * the brace matched by its formatting. It is assumed that we have already
1648 * read the character which starts the group (i.e. the first character of
1649 * "pair").
1651 static void skipToMatch (const char *const pair)
1653 const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
1654 const boolean braceFormatting = (boolean) (cppIsBraceFormat () && braceMatching);
1655 const unsigned int initialLevel = cppGetDirectiveNestLevel ();
1656 const int begin = pair [0], end = pair [1];
1657 const unsigned long inputLineNumber = getInputLineNumber ();
1658 int matchLevel = 1;
1659 int c = '\0';
1660 if (isInputLanguage(Lang_d) && pair[0] == '<')
1661 return; /* ignore e.g. Foo!(x < 2) */
1662 while (matchLevel > 0 && (c = cppGetc ()) != EOF)
1664 if (c == begin)
1666 ++matchLevel;
1667 if (braceFormatting && cppGetDirectiveNestLevel () != initialLevel)
1669 skipToFormattedBraceMatch ();
1670 break;
1673 else if (c == end)
1675 --matchLevel;
1676 if (braceFormatting && cppGetDirectiveNestLevel () != initialLevel)
1678 skipToFormattedBraceMatch ();
1679 break;
1682 /* early out if matching "<>" and we encounter a ";" or "{" to mitigate
1683 * match problems with C++ generics containing a static expression like
1684 * foo<X<Y> bar;
1685 * normally neither ";" nor "{" could appear inside "<>" anyway. */
1686 else if (isInputLanguage (Lang_cpp) && begin == '<' &&
1687 (c == ';' || c == '{'))
1689 cppUngetc (c);
1690 break;
1693 if (c == EOF)
1695 verbose ("%s: failed to find match for '%c' at line %lu\n",
1696 getInputFileName (), begin, inputLineNumber);
1697 if (braceMatching)
1698 longjmp (Exception, (int) ExceptionBraceFormattingError);
1699 else
1700 longjmp (Exception, (int) ExceptionFormattingError);
1704 static void skipParens (void)
1706 const int c = skipToNonWhite ();
1708 if (c == '(')
1709 skipToMatch ("()");
1710 else
1711 cppUngetc (c);
1714 static void skipBraces (void)
1716 const int c = skipToNonWhite ();
1718 if (c == '{')
1719 skipToMatch ("{}");
1720 else
1721 cppUngetc (c);
1724 static keywordId analyzeKeyword (const char *const name)
1726 const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1728 /* ignore D @attributes and Java @annotations(...), but show them in function signatures */
1729 if ((isInputLanguage(Lang_d) || isInputLanguage(Lang_java)) && id == KEYWORD_NONE && name[0] == '@')
1731 skipParens(); /* if annotation has parameters, skip them */
1732 return KEYWORD_CONST;
1734 return id;
1737 static void analyzeIdentifier (tokenInfo *const token)
1739 char *const name = vStringValue (token->name);
1740 const char *replacement = NULL;
1741 boolean parensToo = FALSE;
1743 if (isInputLanguage (Lang_java) ||
1744 ! isIgnoreToken (name, &parensToo, &replacement))
1746 if (replacement != NULL)
1747 token->keyword = analyzeKeyword (replacement);
1748 else
1749 token->keyword = analyzeKeyword (vStringValue (token->name));
1751 if (token->keyword == KEYWORD_NONE)
1752 token->type = TOKEN_NAME;
1753 else
1754 token->type = TOKEN_KEYWORD;
1756 else
1758 initToken (token);
1759 if (parensToo)
1761 int c = skipToNonWhite ();
1763 if (c == '(')
1764 skipToMatch ("()");
1769 static void readIdentifier (tokenInfo *const token, const int firstChar)
1771 vString *const name = token->name;
1772 int c = firstChar;
1774 initToken (token);
1776 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1777 * the ~ and the class name. */
1778 if (isInputLanguage (Lang_cpp) && firstChar == '~')
1780 vStringPut (name, c);
1781 c = skipToNonWhite ();
1786 vStringPut (name, c);
1787 c = cppGetc ();
1788 } while (cppIsident (c) || (isInputLanguage (Lang_vala) && '.' == c));
1789 vStringTerminate (name);
1790 cppUngetc (c); /* unget non-identifier character */
1792 /* Vala supports '?' at end of a type (with or without whitespace before) for nullable types */
1793 if (isInputLanguage (Lang_vala))
1795 c = skipToNonWhite ();
1796 if ('?' == c)
1797 vStringPut (name, c);
1798 else
1799 cppUngetc (c);
1802 analyzeIdentifier (token);
1805 static void readPackageName (tokenInfo *const token, const int firstChar)
1807 vString *const name = token->name;
1808 int c = firstChar;
1810 initToken (token);
1812 while (cppIsident (c) || c == '.')
1814 vStringPut (name, c);
1815 c = cppGetc ();
1817 vStringTerminate (name);
1818 cppUngetc (c); /* unget non-package character */
1821 static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1823 st->declaration = declaration;
1825 if (declaration == DECL_NAMESPACE && !(isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala)))
1827 /* In C++ a namespace is specified one level at a time. */
1828 return;
1830 else
1832 /* In C#, a namespace can also be specified like a Java package name. */
1833 tokenInfo *const token = activeToken (st);
1834 Assert (isType (token, TOKEN_KEYWORD));
1835 readPackageName (token, skipToNonWhite ());
1836 token->type = TOKEN_NAME;
1837 st->gotName = TRUE;
1838 st->haveQualifyingName = TRUE;
1842 static void readPackage (statementInfo *const st)
1844 tokenInfo *const token = activeToken (st);
1845 Assert (isType (token, TOKEN_KEYWORD));
1846 readPackageName (token, skipToNonWhite ());
1847 token->type = TOKEN_NAME;
1848 if (isInputLanguage (Lang_d))
1849 st->declaration = DECL_MODULE;
1850 else
1851 st->declaration = DECL_PACKAGE;
1852 st->gotName = TRUE;
1853 st->haveQualifyingName = TRUE;
1856 static void processName (statementInfo *const st)
1858 Assert (isType (activeToken (st), TOKEN_NAME));
1859 if (st->gotName && st->declaration == DECL_NONE)
1860 st->declaration = DECL_BASE;
1861 st->gotName = TRUE;
1862 st->haveQualifyingName = TRUE;
1865 static void readOperator (statementInfo *const st)
1867 const char *const acceptable = "+-*/%^&|~!=<>,[]";
1868 const tokenInfo* const prev = prevToken (st,1);
1869 tokenInfo *const token = activeToken (st);
1870 vString *const name = token->name;
1871 int c = skipToNonWhite ();
1873 /* When we arrive here, we have the keyword "operator" in 'name'.
1875 if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1876 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1877 ; /* ignore "operator" keyword if preceded by these keywords */
1878 else if (c == '(')
1880 /* Verify whether this is a valid function call (i.e. "()") operator.
1882 if (cppGetc () == ')')
1884 vStringPut (name, ' '); /* always separate operator from keyword */
1885 c = skipToNonWhite ();
1886 if (c == '(')
1887 vStringCatS (name, "()");
1889 else
1891 skipToMatch ("()");
1892 c = cppGetc ();
1895 else if (cppIsident1 (c))
1897 /* Handle "new" and "delete" operators, and conversion functions
1898 * (per 13.3.1.1.2 [2] of the C++ spec).
1900 boolean whiteSpace = TRUE; /* default causes insertion of space */
1903 if (isspace (c))
1904 whiteSpace = TRUE;
1905 else
1907 if (whiteSpace)
1909 vStringPut (name, ' ');
1910 whiteSpace = FALSE;
1912 vStringPut (name, c);
1914 c = cppGetc ();
1915 } while (! isOneOf (c, "(;") && c != EOF);
1916 vStringTerminate (name);
1918 else if (isOneOf (c, acceptable))
1920 vStringPut (name, ' '); /* always separate operator from keyword */
1923 vStringPut (name, c);
1924 c = cppGetc ();
1925 } while (isOneOf (c, acceptable));
1926 vStringTerminate (name);
1929 cppUngetc (c);
1931 token->type = TOKEN_NAME;
1932 token->keyword = KEYWORD_NONE;
1933 processName (st);
1936 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1938 dest->type = src->type;
1939 dest->keyword = src->keyword;
1940 dest->filePosition = src->filePosition;
1941 dest->lineNumber = src->lineNumber;
1942 vStringCopy (dest->name, src->name);
1945 static void setAccess (statementInfo *const st, const accessType laccess)
1947 if (isMember (st))
1949 if (isInputLanguage (Lang_cpp) || isInputLanguage (Lang_d) || isInputLanguage (Lang_ferite))
1951 int c = skipToNonWhite ();
1953 if (c == ':')
1954 reinitStatementWithToken (st, prevToken (st, 1), FALSE);
1955 else
1956 cppUngetc (c);
1958 st->member.accessDefault = laccess;
1960 st->member.access = laccess;
1964 static void discardTypeList (tokenInfo *const token)
1966 int c = skipToNonWhite ();
1967 while (cppIsident1 (c))
1969 readIdentifier (token, c);
1970 c = skipToNonWhite ();
1971 if (c == '.' || c == ',')
1972 c = skipToNonWhite ();
1974 cppUngetc (c);
1977 static void addParentClass (statementInfo *const st, tokenInfo *const token)
1979 if (vStringLength (token->name) > 0 &&
1980 vStringLength (st->parentClasses) > 0)
1982 vStringPut (st->parentClasses, ',');
1984 vStringCat (st->parentClasses, token->name);
1987 static void readParents (statementInfo *const st, const int qualifier)
1989 tokenInfo *const token = newToken ();
1990 tokenInfo *const parent = newToken ();
1991 int c;
1995 c = skipToNonWhite ();
1996 if (cppIsident1 (c))
1998 readIdentifier (token, c);
1999 if (isType (token, TOKEN_NAME))
2000 vStringCat (parent->name, token->name);
2001 else
2003 addParentClass (st, parent);
2004 initToken (parent);
2007 else if (c == qualifier)
2008 vStringPut (parent->name, c);
2009 else if (c == '<')
2010 skipToMatch ("<>");
2011 else if (isType (token, TOKEN_NAME))
2013 addParentClass (st, parent);
2014 initToken (parent);
2016 } while (c != '{' && c != EOF);
2017 cppUngetc (c);
2018 deleteToken (parent);
2019 deleteToken (token);
2022 static void checkIsClassEnum (statementInfo *const st, const declType decl)
2024 if (! isInputLanguage (Lang_cpp) || st->declaration != DECL_ENUM)
2025 st->declaration = decl;
2028 static void processToken (tokenInfo *const token, statementInfo *const st)
2030 switch (token->keyword) /* is it a reserved word? */
2032 default: break;
2034 case KEYWORD_NONE: processName (st); break;
2035 case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
2036 case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
2037 case KEYWORD_CATCH: skipParens (); skipBraces (); break;
2038 case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
2039 case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break;
2040 case KEYWORD_CONST: st->declaration = DECL_BASE; break;
2041 case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
2042 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
2043 case KEYWORD_EXTENDS: readParents (st, '.');
2044 setToken (st, TOKEN_NONE); break;
2045 case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
2046 case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
2047 case KEYWORD_IMPLEMENTS:readParents (st, '.');
2048 setToken (st, TOKEN_NONE); break;
2049 case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
2050 case KEYWORD_INT: st->declaration = DECL_BASE; break;
2051 case KEYWORD_BOOLEAN: st->declaration = DECL_BASE; break;
2052 case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
2053 case KEYWORD_SIZE_T: st->declaration = DECL_BASE; break;
2054 case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
2055 case KEYWORD_LONG: st->declaration = DECL_BASE; break;
2056 case KEYWORD_OPERATOR: readOperator (st); break;
2057 case KEYWORD_MODULE: readPackage (st); break;
2058 case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
2059 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
2060 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
2061 case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
2062 case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
2063 case KEYWORD_STRUCT: checkIsClassEnum (st, DECL_STRUCT); break;
2064 case KEYWORD_STATIC_ASSERT: skipParens (); break;
2065 case KEYWORD_THROWS: discardTypeList (token); break;
2066 case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
2067 case KEYWORD_UNION: st->declaration = DECL_UNION; break;
2068 case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
2069 case KEYWORD_USING: st->declaration = DECL_IGNORE; break;
2070 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
2071 case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
2072 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
2074 case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
2075 case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
2076 case KEYWORD_EVENT:
2078 if (isInputLanguage (Lang_csharp))
2079 st->declaration = DECL_EVENT;
2080 break;
2082 case KEYWORD_SIGNAL:
2084 if (isInputLanguage (Lang_vala))
2085 st->declaration = DECL_SIGNAL;
2086 break;
2088 case KEYWORD_EXTERN:
2090 if (! isInputLanguage (Lang_csharp) || !st->gotName)
2092 /*reinitStatement (st, FALSE);*/
2093 st->scope = SCOPE_EXTERN;
2094 st->declaration = DECL_BASE;
2096 break;
2098 case KEYWORD_STATIC:
2100 if (! isInputLanguage (Lang_java) && ! isInputLanguage (Lang_csharp) && ! isInputLanguage (Lang_vala))
2102 /*reinitStatement (st, FALSE);*/
2103 st->scope = SCOPE_STATIC;
2104 st->declaration = DECL_BASE;
2106 break;
2108 case KEYWORD_IF:
2109 if (isInputLanguage (Lang_d))
2110 { /* static if (is(typeof(__traits(getMember, a, name)) == function)) */
2111 int c = skipToNonWhite ();
2112 if (c == '(')
2113 skipToMatch ("()");
2115 break;
2120 * Parenthesis handling functions
2123 static void restartStatement (statementInfo *const st)
2125 tokenInfo *const save = newToken ();
2126 tokenInfo *token = activeToken (st);
2128 copyToken (save, token);
2129 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
2130 reinitStatement (st, FALSE);
2131 token = activeToken (st);
2132 copyToken (token, save);
2133 deleteToken (save);
2134 processToken (token, st);
2137 /* Skips over a mem-initializer-list of a ctor-initializer, defined as:
2139 * mem-initializer-list:
2140 * mem-initializer, mem-initializer-list
2142 * mem-initializer:
2143 * [::] [nested-name-spec] class-name (...)
2144 * identifier
2146 static void skipMemIntializerList (tokenInfo *const token)
2148 int c;
2152 c = skipToNonWhite ();
2153 while (cppIsident1 (c) || c == ':')
2155 if (c != ':')
2156 readIdentifier (token, c);
2157 c = skipToNonWhite ();
2159 if (c == '<')
2161 skipToMatch ("<>");
2162 c = skipToNonWhite ();
2164 if (c == '(')
2166 skipToMatch ("()");
2167 c = skipToNonWhite ();
2169 } while (c == ',');
2170 cppUngetc (c);
2173 static void skipMacro (statementInfo *const st)
2175 tokenInfo *const prev2 = prevToken (st, 2);
2177 if (isType (prev2, TOKEN_NAME))
2178 retardToken (st);
2179 skipToMatch ("()");
2182 static boolean isDPostArgumentToken(tokenInfo *const token)
2184 switch (token->keyword)
2186 /* Note: some other keywords e.g. immutable are parsed as
2187 * KEYWORD_CONST - see initializeDParser */
2188 case KEYWORD_CONST:
2189 /* template constraint */
2190 case KEYWORD_IF:
2191 /* contracts */
2192 case KEYWORD_IN:
2193 case KEYWORD_OUT:
2194 case KEYWORD_BODY:
2195 return TRUE;
2196 default:
2197 break;
2199 /* @attributes */
2200 if (vStringValue(token->name)[0] == '@')
2201 return TRUE;
2202 return FALSE;
2205 /* Skips over characters following the parameter list. This will be either
2206 * non-ANSI style function declarations or C++ stuff. Our choices:
2208 * C (K&R):
2209 * int func ();
2210 * int func (one, two) int one; float two; {...}
2211 * C (ANSI):
2212 * int func (int one, float two);
2213 * int func (int one, float two) {...}
2214 * C++:
2215 * int foo (...) [const|volatile] [throw (...)];
2216 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2217 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2218 * catch (...) {...}
2220 static boolean skipPostArgumentStuff (
2221 statementInfo *const st, parenInfo *const info)
2223 tokenInfo *const token = activeToken (st);
2224 unsigned int parameters = info->parameterCount;
2225 unsigned int elementCount = 0;
2226 boolean restart = FALSE;
2227 boolean end = FALSE;
2228 int c = skipToNonWhite ();
2232 switch (c)
2234 case ')': break;
2235 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
2236 case '[': skipToMatch ("[]"); break;
2237 case '=': cppUngetc (c); end = TRUE; break;
2238 case '{': cppUngetc (c); end = TRUE; break;
2239 case '}': cppUngetc (c); end = TRUE; break;
2241 case '(':
2243 if (elementCount > 0)
2244 ++elementCount;
2245 skipToMatch ("()");
2246 break;
2249 case ';':
2251 if (parameters == 0 || elementCount < 2)
2253 cppUngetc (c);
2254 end = TRUE;
2256 else if (--parameters == 0)
2257 end = TRUE;
2258 break;
2261 default:
2263 if (cppIsident1 (c))
2265 readIdentifier (token, c);
2266 if (isInputLanguage(Lang_d) && isDPostArgumentToken(token))
2267 token->keyword = KEYWORD_CONST;
2269 switch (token->keyword)
2271 case KEYWORD_ATTRIBUTE: skipParens (); break;
2272 case KEYWORD_THROW: skipParens (); break;
2273 case KEYWORD_CONST: break;
2274 case KEYWORD_NOEXCEPT: break;
2275 case KEYWORD_TRY: break;
2276 case KEYWORD_VOLATILE: break;
2278 case KEYWORD_CATCH: case KEYWORD_CLASS:
2279 case KEYWORD_EXPLICIT: case KEYWORD_EXTERN:
2280 case KEYWORD_FRIEND: case KEYWORD_INLINE:
2281 case KEYWORD_MUTABLE: case KEYWORD_NAMESPACE:
2282 case KEYWORD_NEW: case KEYWORD_OPERATOR:
2283 case KEYWORD_OVERLOAD: case KEYWORD_PRIVATE:
2284 case KEYWORD_PROTECTED: case KEYWORD_PUBLIC:
2285 case KEYWORD_STATIC: case KEYWORD_TEMPLATE:
2286 case KEYWORD_TYPEDEF: case KEYWORD_TYPENAME:
2287 case KEYWORD_USING: case KEYWORD_VIRTUAL:
2288 /* Never allowed within parameter declarations.
2290 restart = TRUE;
2291 end = TRUE;
2292 break;
2294 default:
2295 /* "override" and "final" are only keywords in the declaration of a virtual
2296 * member function, so need to be handled specially, not as keywords */
2297 if (isInputLanguage(Lang_cpp) && isType (token, TOKEN_NAME) &&
2298 (strcmp ("override", vStringValue (token->name)) == 0 ||
2299 strcmp ("final", vStringValue (token->name)) == 0))
2301 else if (isType (token, TOKEN_NONE))
2303 else if (info->isKnrParamList && info->parameterCount > 0)
2304 ++elementCount;
2305 else
2307 /* If we encounter any other identifier immediately
2308 * following an empty parameter list, this is almost
2309 * certainly one of those Microsoft macro "thingies"
2310 * that the automatic source code generation sticks
2311 * in. Terminate the current statement.
2313 restart = TRUE;
2314 end = TRUE;
2316 break;
2321 if (! end)
2323 c = skipToNonWhite ();
2324 if (c == EOF)
2325 end = TRUE;
2327 } while (! end);
2329 if (restart)
2330 restartStatement (st);
2331 else
2332 setToken (st, TOKEN_NONE);
2334 return (boolean) (c != EOF);
2337 static void skipJavaThrows (statementInfo *const st)
2339 tokenInfo *const token = activeToken (st);
2340 int c = skipToNonWhite ();
2342 if (cppIsident1 (c))
2344 readIdentifier (token, c);
2345 if (token->keyword == KEYWORD_THROWS)
2349 c = skipToNonWhite ();
2350 if (cppIsident1 (c))
2352 readIdentifier (token, c);
2353 c = skipToNonWhite ();
2355 } while (c == '.' || c == ',');
2358 cppUngetc (c);
2359 setToken (st, TOKEN_NONE);
2362 static void skipValaPostParens (statementInfo *const st)
2364 tokenInfo *const token = activeToken (st);
2365 int c = skipToNonWhite ();
2367 while (cppIsident1 (c))
2369 readIdentifier (token, c);
2370 if (token->keyword == KEYWORD_ATTRIBUTE)
2372 /* parse contracts */
2373 skipParens ();
2374 c = skipToNonWhite ();
2376 else if (token->keyword == KEYWORD_THROWS)
2380 c = skipToNonWhite ();
2381 if (cppIsident1 (c))
2383 readIdentifier (token, c);
2384 c = skipToNonWhite ();
2386 } while (c == '.' || c == ',');
2388 else
2389 break;
2391 cppUngetc (c);
2392 setToken (st, TOKEN_NONE);
2395 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2397 const unsigned long inputLineNumber = getInputLineNumber ();
2398 int c = skipToNonWhite ();
2400 cppUngetc (c);
2401 if (isOneOf (c, "{;,="))
2403 else if (isInputLanguage (Lang_java))
2404 skipJavaThrows (st);
2405 else if (isInputLanguage (Lang_vala))
2406 skipValaPostParens(st);
2407 else
2409 if (! skipPostArgumentStuff (st, info))
2411 verbose (
2412 "%s: confusing argument declarations beginning at line %lu\n",
2413 getInputFileName (), inputLineNumber);
2414 longjmp (Exception, (int) ExceptionFormattingError);
2419 static int parseParens (statementInfo *const st, parenInfo *const info)
2421 tokenInfo *const token = activeToken (st);
2422 unsigned int identifierCount = 0;
2423 unsigned int depth = 1;
2424 boolean firstChar = TRUE;
2425 int nextChar = '\0';
2427 info->parameterCount = 1;
2430 int c = skipToNonWhite ();
2432 switch (c)
2434 case '&':
2435 case '*':
2437 /* DEBUG_PRINT("parseParens, po++\n"); */
2438 info->isKnrParamList = FALSE;
2439 if (identifierCount == 0)
2440 info->isParamList = FALSE;
2441 initToken (token);
2442 break;
2444 case ':':
2446 info->isKnrParamList = FALSE;
2447 break;
2449 case '.':
2451 info->isNameCandidate = FALSE;
2452 info->isKnrParamList = FALSE;
2453 break;
2455 case ',':
2457 info->isNameCandidate = FALSE;
2458 if (info->isKnrParamList)
2460 ++info->parameterCount;
2461 identifierCount = 0;
2463 break;
2465 case '=':
2467 info->isKnrParamList = FALSE;
2468 info->isNameCandidate = FALSE;
2469 if (firstChar)
2471 info->isParamList = FALSE;
2472 skipMacro (st);
2473 depth = 0;
2475 break;
2477 case '[':
2479 info->isKnrParamList = FALSE;
2480 skipToMatch ("[]");
2481 break;
2483 case '<':
2485 info->isKnrParamList = FALSE;
2486 skipToMatch ("<>");
2487 break;
2489 case ')':
2491 if (firstChar)
2492 info->parameterCount = 0;
2493 --depth;
2494 break;
2496 case '(':
2498 info->isKnrParamList = FALSE;
2499 if (firstChar)
2501 info->isNameCandidate = FALSE;
2502 cppUngetc (c);
2503 skipMacro (st);
2504 depth = 0;
2506 else if (isType (token, TOKEN_PAREN_NAME))
2508 c = skipToNonWhite ();
2509 if (c == '*') /* check for function pointer */
2511 skipToMatch ("()");
2512 c = skipToNonWhite ();
2513 if (c == '(')
2514 skipToMatch ("()");
2516 else
2518 cppUngetc (c);
2519 cppUngetc ('(');
2520 info->nestedArgs = TRUE;
2523 else
2524 ++depth;
2525 break;
2528 default:
2530 if (cppIsident1 (c))
2532 if (++identifierCount > 1)
2533 info->isKnrParamList = FALSE;
2534 readIdentifier (token, c);
2535 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2536 token->type = TOKEN_PAREN_NAME;
2537 else if (isType (token, TOKEN_KEYWORD))
2539 info->isKnrParamList = FALSE;
2540 info->isNameCandidate = FALSE;
2543 else if (isInputLanguage(Lang_d) && c == '!')
2544 { /* D template instantiation */
2545 info->isNameCandidate = FALSE;
2546 info->isKnrParamList = FALSE;
2548 else
2550 info->isParamList = FALSE;
2551 info->isKnrParamList = FALSE;
2552 info->isNameCandidate = FALSE;
2553 info->invalidContents = TRUE;
2555 break;
2558 firstChar = FALSE;
2559 } while (! info->nestedArgs && depth > 0 &&
2560 (info->isKnrParamList || info->isNameCandidate));
2562 if (! info->nestedArgs) while (depth > 0)
2564 skipToMatch ("()");
2565 --depth;
2567 if (st->argEndPosition == 0)
2568 st->argEndPosition = mio_tell (File.mio);
2570 if (! info->isNameCandidate)
2571 initToken (token);
2573 return nextChar;
2576 static void initParenInfo (parenInfo *const info)
2578 info->isParamList = TRUE;
2579 info->isKnrParamList = TRUE;
2580 info->isNameCandidate = TRUE;
2581 info->invalidContents = FALSE;
2582 info->nestedArgs = FALSE;
2583 info->parameterCount = 0;
2586 static void analyzeParens (statementInfo *const st)
2588 tokenInfo *const prev = prevToken (st, 1);
2590 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2592 tokenInfo *const token = activeToken (st);
2593 parenInfo info;
2594 int c;
2596 initParenInfo (&info);
2597 parseParens (st, &info);
2598 c = skipToNonWhite ();
2599 cppUngetc (c);
2600 if (info.invalidContents)
2602 reinitStatement (st, FALSE);
2604 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2605 ! st->gotParenName &&
2606 (! info.isParamList || ! st->haveQualifyingName ||
2607 c == '(' ||
2608 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2609 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2611 token->type = TOKEN_NAME;
2612 processName (st);
2613 st->gotParenName = TRUE;
2614 if (isInputLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME))
2616 st->declaration = DECL_FUNCTION_TEMPLATE;
2617 copyToken (st->blockName, prev);
2620 else if (! st->gotArgs && info.isParamList)
2622 st->gotArgs = TRUE;
2623 setToken (st, TOKEN_ARGS);
2624 advanceToken (st);
2625 analyzePostParens (st, &info);
2627 else
2628 setToken (st, TOKEN_NONE);
2633 * Token parsing functions
2636 static void addContext (statementInfo *const st, const tokenInfo* const token)
2638 if (isType (token, TOKEN_NAME))
2640 if (vStringLength (st->context->name) > 0)
2642 if (isInputLanguage (Lang_c) || isInputLanguage (Lang_cpp))
2643 vStringCatS (st->context->name, "::");
2644 else if (isInputLanguage (Lang_java) ||
2645 isInputLanguage (Lang_d) || isInputLanguage (Lang_ferite) ||
2646 isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
2647 vStringCatS (st->context->name, ".");
2649 vStringCat (st->context->name, token->name);
2650 st->context->type = TOKEN_NAME;
2654 static boolean inheritingDeclaration (declType decl)
2656 /* enum base types */
2657 if (decl == DECL_ENUM)
2659 return (boolean) (isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) ||
2660 isInputLanguage (Lang_d));
2662 return (boolean) (
2663 decl == DECL_CLASS ||
2664 decl == DECL_STRUCT ||
2665 decl == DECL_INTERFACE);
2668 static void processColon (statementInfo *const st)
2670 int c = cppGetc ();
2671 const boolean doubleColon = (boolean) (c == ':');
2673 if (doubleColon)
2675 setToken (st, TOKEN_DOUBLE_COLON);
2676 st->haveQualifyingName = FALSE;
2678 else
2680 cppUngetc (c);
2681 if ((isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_d) ||
2682 isInputLanguage (Lang_vala)) &&
2683 inheritingDeclaration (st->declaration))
2685 readParents (st, ':');
2687 else if (parentDecl (st) == DECL_STRUCT || parentDecl (st) == DECL_CLASS)
2689 c = skipToOneOf (",;");
2690 if (c == ',')
2691 setToken (st, TOKEN_COMMA);
2692 else if (c == ';')
2693 setToken (st, TOKEN_SEMICOLON);
2695 else
2697 const tokenInfo *const prev = prevToken (st, 1);
2698 const tokenInfo *const prev2 = prevToken (st, 2);
2699 if (prev->keyword == KEYWORD_DEFAULT ||
2700 prev2->keyword == KEYWORD_CASE ||
2701 st->parent != NULL)
2703 reinitStatement (st, FALSE);
2709 /* Skips over any initializing value which may follow an '=' character in a
2710 * variable definition.
2712 static int skipInitializer (statementInfo *const st)
2714 boolean done = FALSE;
2715 int c;
2717 while (! done)
2719 c = skipToNonWhite ();
2721 if (c == EOF)
2722 longjmp (Exception, (int) ExceptionFormattingError);
2723 else switch (c)
2725 case ',':
2726 case ';': done = TRUE; break;
2728 case '0':
2729 if (st->implementation == IMP_VIRTUAL)
2730 st->implementation = IMP_PURE_VIRTUAL;
2731 break;
2733 case '[': skipToMatch ("[]"); break;
2734 case '(': skipToMatch ("()"); break;
2735 case '{': skipToMatch ("{}"); break;
2737 case '}':
2738 if (insideEnumBody (st))
2739 done = TRUE;
2740 else if (! cppIsBraceFormat ())
2742 verbose ("%s: unexpected closing brace at line %lu\n",
2743 getInputFileName (), getInputLineNumber ());
2744 longjmp (Exception, (int) ExceptionBraceFormattingError);
2746 break;
2748 default: break;
2751 return c;
2754 static void processInitializer (statementInfo *const st)
2756 const boolean inEnumBody = insideEnumBody (st);
2757 const int c = skipInitializer (st);
2759 if (c == ';')
2760 setToken (st, TOKEN_SEMICOLON);
2761 else if (c == ',')
2762 setToken (st, TOKEN_COMMA);
2763 else if (c == '}' && inEnumBody)
2765 cppUngetc (c);
2766 setToken (st, TOKEN_COMMA);
2768 if (st->scope == SCOPE_EXTERN)
2769 st->scope = SCOPE_GLOBAL;
2772 static void parseIdentifier (statementInfo *const st, const int c)
2774 tokenInfo *const token = activeToken (st);
2776 readIdentifier (token, c);
2777 if (! isType (token, TOKEN_NONE))
2778 processToken (token, st);
2781 static void parseGeneralToken (statementInfo *const st, const int c)
2783 const tokenInfo *const prev = prevToken (st, 1);
2785 if (cppIsident1(c))
2787 parseIdentifier (st, c);
2788 if (isType (st->context, TOKEN_NAME) &&
2789 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2791 initToken (st->context);
2794 else if (isExternCDecl (st, c))
2796 st->declaration = DECL_NOMANGLE;
2797 st->scope = SCOPE_GLOBAL;
2801 /* Reads characters from the pre-processor and assembles tokens, setting
2802 * the current statement state.
2804 static void nextToken (statementInfo *const st)
2806 int c;
2807 tokenInfo *token = activeToken (st);
2810 c = skipToNonWhite();
2811 switch (c)
2813 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2814 case '(': analyzeParens (st); token = activeToken (st); break;
2815 case '*': setToken (st, TOKEN_STAR); break;
2816 case ',': setToken (st, TOKEN_COMMA); break;
2817 case ':': processColon (st); break;
2818 case ';': setToken (st, TOKEN_SEMICOLON); break;
2819 case '<': skipToMatch ("<>"); break;
2820 case '=': processInitializer (st); break;
2821 case '[':
2822 /* Hack for Vala: [..] can be a function attribute.
2823 * Seems not to have bad side effects, but have to test it more. */
2824 if (!isInputLanguage (Lang_vala))
2825 setToken (st, TOKEN_ARRAY);
2826 skipToMatch ("[]");
2827 break;
2828 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2829 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2830 default: parseGeneralToken (st, c); break;
2832 } while (isType (token, TOKEN_NONE));
2834 if (isType (token, TOKEN_SEMICOLON) && st->parent)
2835 st->parent->nSemicolons ++;
2837 /* We want to know about non-keyword variable types */
2838 if (TOKEN_NONE == st->firstToken->type)
2840 if ((TOKEN_NAME == token->type) || isDataTypeKeyword(token))
2841 copyToken(st->firstToken, token);
2846 * Scanning support functions
2848 static unsigned int contextual_fake_count = 0;
2849 static statementInfo *CurrentStatement = NULL;
2851 static statementInfo *newStatement (statementInfo *const parent)
2853 statementInfo *const st = xMalloc (1, statementInfo);
2854 unsigned int i;
2856 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2857 st->token [i] = newToken ();
2859 st->context = newToken ();
2860 st->blockName = newToken ();
2861 st->parentClasses = vStringNew ();
2862 st->firstToken = newToken();
2864 initStatement (st, parent);
2865 CurrentStatement = st;
2867 return st;
2870 static void deleteStatement (void)
2872 statementInfo *const st = CurrentStatement;
2873 statementInfo *const parent = st->parent;
2874 unsigned int i;
2876 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2878 deleteToken (st->token [i]); st->token [i] = NULL;
2880 deleteToken (st->blockName); st->blockName = NULL;
2881 deleteToken (st->context); st->context = NULL;
2882 vStringDelete (st->parentClasses); st->parentClasses = NULL;
2883 deleteToken(st->firstToken);
2884 eFree (st);
2885 CurrentStatement = parent;
2888 static void deleteAllStatements (void)
2890 while (CurrentStatement != NULL)
2891 deleteStatement ();
2894 static boolean isStatementEnd (const statementInfo *const st)
2896 const tokenInfo *const token = activeToken (st);
2897 boolean isEnd;
2899 if (isType (token, TOKEN_SEMICOLON))
2900 isEnd = TRUE;
2901 else if (isType (token, TOKEN_BRACE_CLOSE))
2902 /* Java, D, C#, Vala do not require semicolons to end a block. Neither do
2903 * C++ namespaces. All other blocks require a semicolon to terminate them.
2905 isEnd = (boolean) (isInputLanguage (Lang_java) || isInputLanguage (Lang_d) ||
2906 isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala) ||
2907 ! isContextualStatement (st));
2908 else
2909 isEnd = FALSE;
2911 return isEnd;
2914 static void checkStatementEnd (statementInfo *const st)
2916 const tokenInfo *const token = activeToken (st);
2917 boolean comma = isType (token, TOKEN_COMMA);
2919 if (comma || isStatementEnd (st))
2921 reinitStatementWithToken (st, activeToken (st), comma);
2923 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2924 cppEndStatement ();
2926 else
2928 cppBeginStatement ();
2929 advanceToken (st);
2933 static void nest (statementInfo *const st, const unsigned int nestLevel)
2935 switch (st->declaration)
2937 case DECL_CLASS:
2938 case DECL_ENUM:
2939 case DECL_INTERFACE:
2940 case DECL_NAMESPACE:
2941 case DECL_NOMANGLE:
2942 case DECL_STRUCT:
2943 case DECL_UNION:
2944 createTags (nestLevel, st);
2945 break;
2946 default:
2947 skipToMatch ("{}");
2948 break;
2950 advanceToken (st);
2951 setToken (st, TOKEN_BRACE_CLOSE);
2954 static void tagCheck (statementInfo *const st)
2956 const tokenInfo *const token = activeToken (st);
2957 const tokenInfo *const prev = prevToken (st, 1);
2958 const tokenInfo *const prev2 = prevToken (st, 2);
2960 switch (token->type)
2962 case TOKEN_NAME:
2964 if (insideEnumBody (st) &&
2965 /* Java enumerations can contain members after a semicolon */
2966 (! isInputLanguage(Lang_java) || st->parent->nSemicolons < 1))
2967 qualifyEnumeratorTag (st, token);
2968 break;
2970 #if 0
2971 case TOKEN_PACKAGE:
2973 if (st->haveQualifyingName)
2974 makeTag (token, st, FALSE, TAG_PACKAGE);
2975 break;
2977 #endif
2978 case TOKEN_BRACE_OPEN:
2980 if (isType (prev, TOKEN_ARGS))
2982 if (st->declaration == DECL_FUNCTION_TEMPLATE)
2983 qualifyFunctionTag (st, st->blockName);
2984 else if (st->haveQualifyingName)
2986 if (isType (prev2, TOKEN_NAME))
2987 copyToken (st->blockName, prev2);
2988 /* D structure templates */
2989 if (isInputLanguage (Lang_d) &&
2990 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT ||
2991 st->declaration == DECL_INTERFACE || st->declaration == DECL_NAMESPACE))
2992 qualifyBlockTag (st, prev2);
2993 else
2995 st->declaration = DECL_FUNCTION;
2996 qualifyFunctionTag (st, prev2);
3000 else if (isContextualStatement (st))
3002 tokenInfo *name_token = (tokenInfo *)prev;
3003 boolean free_name_token = FALSE;
3005 /* C++ 11 allows class <name> final { ... } */
3006 if (isInputLanguage (Lang_cpp) && isType (prev, TOKEN_NAME) &&
3007 strcmp("final", vStringValue(prev->name)) == 0 &&
3008 isType(prev2, TOKEN_NAME))
3010 name_token = (tokenInfo *)prev2;
3011 copyToken (st->blockName, name_token);
3013 else if (isType (name_token, TOKEN_NAME))
3015 if (!isInputLanguage (Lang_vala))
3016 copyToken (st->blockName, name_token);
3017 else
3019 switch (st->declaration)
3021 case DECL_CLASS:
3022 case DECL_ENUM:
3023 case DECL_INTERFACE:
3024 case DECL_NAMESPACE:
3025 case DECL_STRUCT:
3026 copyToken (st->blockName, name_token);
3027 break;
3029 /* anything else can be a property */
3030 default:
3031 /* makeTag (prev, st, FALSE, TAG_PROPERTY); */
3032 /* FIXME: temporary hack to get properties shown */
3033 makeTag (prev, st, FALSE, TAG_FIELD);
3034 break;
3038 else if (isInputLanguage (Lang_csharp))
3039 makeTag (prev, st, FALSE, TAG_PROPERTY);
3040 else
3042 tokenInfo *contextual_token = (tokenInfo *)prev;
3043 if(isContextualKeyword (contextual_token))
3045 char buffer[64];
3047 name_token = newToken ();
3048 free_name_token = TRUE;
3049 copyToken (name_token, contextual_token);
3051 sprintf(buffer, "anon_%s_%d", name_token->name->buffer, contextual_fake_count++);
3052 vStringClear(name_token->name);
3053 vStringCatS(name_token->name, buffer);
3055 name_token->type = TOKEN_NAME;
3056 name_token->keyword = KEYWORD_NONE;
3058 advanceToken (st);
3059 contextual_token = activeToken (st);
3060 copyToken (contextual_token, token);
3061 copyToken ((tokenInfo *const)token, name_token);
3062 copyToken (st->blockName, name_token);
3063 copyToken (st->firstToken, name_token);
3066 qualifyBlockTag (st, name_token);
3067 if (free_name_token)
3068 deleteToken (name_token);
3070 break;
3072 case TOKEN_ARRAY:
3073 case TOKEN_SEMICOLON:
3074 case TOKEN_COMMA:
3076 if (insideEnumBody (st) &&
3077 /* Java enumerations can contain members after a semicolon */
3078 (! isInputLanguage (Lang_java) || st->parent->nSemicolons < 2))
3080 else if (isType (prev, TOKEN_NAME))
3082 if (isContextualKeyword (prev2))
3083 makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
3084 else
3085 qualifyVariableTag (st, prev);
3087 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
3089 qualifyFunctionDeclTag (st, prev2);
3091 break;
3093 default:
3094 break;
3098 /* Parses the current file and decides whether to write out and tags that
3099 * are discovered.
3101 static void createTags (const unsigned int nestLevel,
3102 statementInfo *const parent)
3104 statementInfo *const st = newStatement (parent);
3106 DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
3107 while (TRUE)
3109 tokenInfo *token;
3111 nextToken (st);
3112 token = activeToken (st);
3113 if (isType (token, TOKEN_BRACE_CLOSE))
3115 if (nestLevel > 0)
3116 break;
3117 else
3119 verbose ("%s: unexpected closing brace at line %lu\n",
3120 getInputFileName (), getInputLineNumber ());
3121 longjmp (Exception, (int) ExceptionBraceFormattingError);
3124 else if (isType (token, TOKEN_DOUBLE_COLON))
3126 addContext (st, prevToken (st, 1));
3127 advanceToken (st);
3129 else
3131 tagCheck (st);/* this can add new token */
3132 if (isType (activeToken (st), TOKEN_BRACE_OPEN))
3133 nest (st, nestLevel + 1);
3134 checkStatementEnd (st);
3137 deleteStatement ();
3138 DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
3141 static boolean findCTags (const unsigned int passCount)
3143 exception_t exception;
3144 boolean retry;
3146 contextual_fake_count = 0;
3148 Assert (passCount < 3);
3149 cppInit ((boolean) (passCount > 1), isInputLanguage (Lang_csharp), isInputLanguage (Lang_cpp), &(CKinds [CK_DEFINE]));
3151 exception = (exception_t) setjmp (Exception);
3152 retry = FALSE;
3154 if (exception == ExceptionNone)
3156 createTags (0, NULL);
3158 else
3160 deleteAllStatements ();
3161 if (exception == ExceptionBraceFormattingError && passCount == 1)
3163 retry = TRUE;
3164 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3165 getInputFileName ());
3168 cppTerminate ();
3169 return retry;
3172 static void buildKeywordHash (const langType language, unsigned int idx)
3174 const size_t count = ARRAY_SIZE (KeywordTable);
3175 size_t i;
3176 for (i = 0 ; i < count ; ++i)
3178 const keywordDesc* const p = &KeywordTable [i];
3179 if (p->isValid [idx])
3180 addKeyword (p->name, language, (int) p->id);
3184 static void initializeCParser (const langType language)
3186 Lang_c = language;
3187 buildKeywordHash (language, 0);
3190 static void initializeCppParser (const langType language)
3192 Lang_cpp = language;
3193 buildKeywordHash (language, 1);
3196 static void initializeJavaParser (const langType language)
3198 Lang_java = language;
3199 buildKeywordHash (language, 3);
3202 static void initializeDParser (const langType language)
3204 /* treat these like const - some are for parsing like const(Type), some are just
3205 * function attributes */
3206 const char *const_aliases[] = {"immutable", "nothrow", "pure", "shared", NULL};
3207 const char **s;
3209 Lang_d = language;
3210 buildKeywordHash (language, 6);
3212 for (s = const_aliases; *s != NULL; s++)
3214 addKeyword (*s, language, KEYWORD_CONST);
3216 /* other keyword aliases */
3217 addKeyword ("alias", language, KEYWORD_TYPEDEF);
3218 /* skip 'static assert(...)' like 'static if (...)' */
3219 addKeyword ("assert", language, KEYWORD_IF);
3220 addKeyword ("unittest", language, KEYWORD_BODY); /* ignore */
3221 addKeyword ("version", language, KEYWORD_NAMESPACE); /* parse block */
3224 static void initializeGLSLParser (const langType language)
3226 Lang_glsl = language;
3227 buildKeywordHash (language, 0); /* C keywords */
3230 static void initializeFeriteParser (const langType language)
3232 Lang_ferite = language;
3233 buildKeywordHash (language, 1); /* C++ keywords */
3236 static void initializeCsharpParser (const langType language)
3238 Lang_csharp = language;
3239 buildKeywordHash (language, 2);
3242 static void initializeValaParser (const langType language)
3244 Lang_vala = language;
3245 buildKeywordHash (language, 5);
3247 /* keyword aliases */
3248 addKeyword ("ensures", language, KEYWORD_ATTRIBUTE); /* ignore */
3249 addKeyword ("errordomain", language, KEYWORD_ENUM); /* looks like enum */
3250 addKeyword ("requires", language, KEYWORD_ATTRIBUTE); /* ignore */
3253 extern parserDefinition* CParser (void)
3255 static const char *const extensions [] = { "c", "pc", "sc", NULL };
3256 parserDefinition* def = parserNew ("C");
3257 def->kinds = CKinds;
3258 def->kindCount = ARRAY_SIZE (CKinds);
3259 def->extensions = extensions;
3260 def->parser2 = findCTags;
3261 def->initialize = initializeCParser;
3262 return def;
3265 extern parserDefinition* CppParser (void)
3267 static const char *const extensions [] = {
3268 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3269 "i",
3270 #ifndef CASE_INSENSITIVE_FILENAMES
3271 "C", "H",
3272 #endif
3273 NULL
3275 parserDefinition* def = parserNew ("C++");
3276 def->kinds = CKinds;
3277 def->kindCount = ARRAY_SIZE (CKinds);
3278 def->extensions = extensions;
3279 def->parser2 = findCTags;
3280 def->initialize = initializeCppParser;
3281 return def;
3284 extern parserDefinition* JavaParser (void)
3286 static const char *const extensions [] = { "java", NULL };
3287 parserDefinition* def = parserNew ("Java");
3288 def->kinds = JavaKinds;
3289 def->kindCount = ARRAY_SIZE (JavaKinds);
3290 def->extensions = extensions;
3291 def->parser2 = findCTags;
3292 def->initialize = initializeJavaParser;
3293 return def;
3296 extern parserDefinition* DParser (void)
3298 static const char *const extensions [] = { "d", "di", NULL };
3299 parserDefinition* def = parserNew ("D");
3300 def->kinds = DKinds;
3301 def->kindCount = ARRAY_SIZE (DKinds);
3302 def->extensions = extensions;
3303 def->parser2 = findCTags;
3304 def->initialize = initializeDParser;
3305 return def;
3308 extern parserDefinition* GLSLParser (void)
3310 static const char *const extensions [] = { "glsl", "frag", "vert", NULL };
3311 parserDefinition* def = parserNew ("GLSL");
3312 def->kinds = CKinds;
3313 def->kindCount = ARRAY_SIZE (CKinds);
3314 def->extensions = extensions;
3315 def->parser2 = findCTags;
3316 def->initialize = initializeGLSLParser;
3317 return def;
3320 extern parserDefinition* FeriteParser (void)
3322 static const char *const extensions [] = { "fe", NULL };
3323 parserDefinition* def = parserNew ("Ferite");
3324 def->kinds = CKinds;
3325 def->kindCount = ARRAY_SIZE (CKinds);
3326 def->extensions = extensions;
3327 def->parser2 = findCTags;
3328 def->initialize = initializeFeriteParser;
3329 return def;
3332 extern parserDefinition* CsharpParser (void)
3334 static const char *const extensions [] = { "cs", NULL };
3335 parserDefinition* def = parserNew ("C#");
3336 def->kinds = CsharpKinds;
3337 def->kindCount = ARRAY_SIZE (CsharpKinds);
3338 def->extensions = extensions;
3339 def->parser2 = findCTags;
3340 def->initialize = initializeCsharpParser;
3341 return def;
3344 extern parserDefinition* ValaParser (void)
3346 static const char *const extensions [] = { "vala", NULL };
3347 parserDefinition* def = parserNew ("Vala");
3348 def->kinds = ValaKinds;
3349 def->kindCount = ARRAY_SIZE (ValaKinds);
3350 def->extensions = extensions;
3351 def->parser2 = findCTags;
3352 def->initialize = initializeValaParser;
3353 return def;
3355 /* vi:set tabstop=4 shiftwidth=4: */