Version bump.
[geany-mirror.git] / tagmanager / c.c
blob3ead1b5afe3a5d25bf884084a5615f2bf9deb199
1 /*
3 * Copyright (c) 1996-2001, Darren Hiebert
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
8 * This module contains functions for parsing and scanning C, C++, D and Java
9 * source files.
13 * INCLUDE FILES
15 #include "general.h" /* must always come first */
17 #include <string.h>
18 #include <setjmp.h>
20 #include "entry.h"
21 #include "get.h"
22 #include "keyword.h"
23 #include "main.h"
24 #include "options.h"
25 #include "parse.h"
26 #include "read.h"
29 * MACROS
32 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
33 #define parentDecl(st) ((st)->parent == NULL ? \
34 DECL_NONE : (st)->parent->declaration)
35 #define isType(token,t) (boolean) ((token)->type == (t))
36 #define insideEnumBody(st) (boolean) ((st)->parent == NULL ? FALSE : \
37 ((st)->parent->declaration == DECL_ENUM))
38 #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
39 ! (st)->haveQualifyingName && \
40 (st)->scope == SCOPE_EXTERN)
42 #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
45 * DATA DECLARATIONS
48 enum { NumTokens = 12 };
50 typedef enum eException
52 ExceptionNone, ExceptionEOF, ExceptionFormattingError,
53 ExceptionBraceFormattingError
54 } exception_t;
56 /* Used to specify type of keyword.
58 typedef enum eKeywordId
60 KEYWORD_NONE = -1,
61 KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT, KEYWORD_ALIAS,
62 KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
63 KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT, KEYWORD_BODY,
64 KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
65 KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
66 KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
67 KEYWORD_DOUBLE,
68 KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
69 KEYWORD_EXTENDS, KEYWORD_EVENT,
70 KEYWORD_FINAL, KEYWORD_FINALLY, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FRIEND, KEYWORD_FUNCTION,
71 KEYWORD_GET, KEYWORD_GOTO,
72 KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_IN, KEYWORD_INLINE, KEYWORD_INT,
73 KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
74 KEYWORD_INTERNAL,
75 KEYWORD_LOCAL, KEYWORD_LONG,
76 KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
77 KEYWORD_MODULE, KEYWORD_MUTABLE,
78 KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE,
79 KEYWORD_OPERATOR, KEYWORD_OUT, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
80 KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE,
81 KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
82 KEYWORD_REF, KEYWORD_REGISTER, KEYWORD_RETURN,
83 KEYWORD_SHADOW, KEYWORD_STATE,
84 KEYWORD_SET, KEYWORD_SHORT, KEYWORD_SIGNAL, KEYWORD_SIGNED, KEYWORD_SIZE_T, KEYWORD_STATIC, KEYWORD_STRING,
85 KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
86 KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
87 KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
88 KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
89 KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
90 KEYWORD_USING,
91 KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
92 KEYWORD_WCHAR_T, KEYWORD_WEAK, KEYWORD_WHILE
93 } keywordId;
95 /* Used to determine whether keyword is valid for the current language and
96 * what its ID is.
98 typedef struct sKeywordDesc
100 const char *name;
101 keywordId id;
102 short isValid [7]; /* indicates languages for which kw is valid */
103 } keywordDesc;
105 /* Used for reporting the type of object parsed by nextToken ().
107 typedef enum eTokenType
109 TOKEN_NONE, /* none */
110 TOKEN_ARGS, /* a parenthetical pair and its contents */
111 TOKEN_BRACE_CLOSE,
112 TOKEN_BRACE_OPEN,
113 TOKEN_COMMA, /* the comma character */
114 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
115 TOKEN_KEYWORD,
116 TOKEN_NAME, /* an unknown name */
117 TOKEN_PACKAGE, /* a Java package name */
118 TOKEN_PAREN_NAME, /* a single name in parentheses */
119 TOKEN_SEMICOLON, /* the semicolon character */
120 TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
121 TOKEN_STAR, /* pointer detection */
122 TOKEN_ARRAY, /* array detection */
123 TOKEN_COUNT
124 } tokenType;
126 /* This describes the scoping of the current statement.
128 typedef enum eTagScope
130 SCOPE_GLOBAL, /* no storage class specified */
131 SCOPE_STATIC, /* static storage class */
132 SCOPE_EXTERN, /* external storage class */
133 SCOPE_FRIEND, /* declares access only */
134 SCOPE_TYPEDEF, /* scoping depends upon context */
135 SCOPE_COUNT
136 } tagScope;
138 typedef enum eDeclaration
140 DECL_NONE,
141 DECL_BASE, /* base type (default) */
142 DECL_CLASS,
143 DECL_ENUM,
144 DECL_EVENT,
145 DECL_SIGNAL,
146 DECL_FUNCTION,
147 DECL_IGNORE, /* non-taggable "declaration" */
148 DECL_INTERFACE,
149 DECL_MODULE,
150 DECL_NAMESPACE,
151 DECL_NOMANGLE, /* C++ name demangling block */
152 DECL_PACKAGE,
153 DECL_STRUCT,
154 DECL_UNION,
155 DECL_COUNT
156 } declType;
158 typedef enum eVisibilityType
160 ACCESS_UNDEFINED,
161 ACCESS_PRIVATE,
162 ACCESS_PROTECTED,
163 ACCESS_PUBLIC,
164 ACCESS_DEFAULT, /* Java-specific */
165 ACCESS_COUNT
166 } accessType;
168 /* Information about the parent class of a member (if any).
170 typedef struct sMemberInfo
172 accessType access; /* access of current statement */
173 accessType accessDefault; /* access default for current statement */
174 } memberInfo;
176 typedef struct sTokenInfo
178 tokenType type;
179 keywordId keyword;
180 vString* name; /* the name of the token */
181 unsigned long lineNumber; /* line number of tag */
182 fpos_t filePosition; /* file position of line containing name */
183 int bufferPosition; /* buffer position of line containing name */
184 } tokenInfo;
186 typedef enum eImplementation
188 IMP_DEFAULT,
189 IMP_ABSTRACT,
190 IMP_VIRTUAL,
191 IMP_PURE_VIRTUAL,
192 IMP_COUNT
193 } impType;
195 /* Describes the statement currently undergoing analysis.
197 typedef struct sStatementInfo
199 tagScope scope;
200 declType declaration; /* specifier associated with TOKEN_SPEC */
201 boolean gotName; /* was a name parsed yet? */
202 boolean haveQualifyingName; /* do we have a name we are considering? */
203 boolean gotParenName; /* was a name inside parentheses parsed yet? */
204 boolean gotArgs; /* was a list of parameters parsed yet? */
205 impType implementation; /* abstract or concrete implementation? */
206 unsigned int tokenIndex; /* currently active token */
207 tokenInfo* token [((int) NumTokens)];
208 tokenInfo* context; /* accumulated scope of current statement */
209 tokenInfo* blockName; /* name of current block */
210 memberInfo member; /* information regarding parent class/struct */
211 vString* parentClasses; /* parent classes */
212 struct sStatementInfo *parent; /* statement we are nested within */
213 long argEndPosition; /* Position where argument list ended */
214 tokenInfo* firstToken; /* First token in the statement */
215 } statementInfo;
217 /* Describes the type of tag being generated.
219 typedef enum eTagType
221 TAG_UNDEFINED,
222 TAG_CLASS, /* class name */
223 TAG_ENUM, /* enumeration name */
224 TAG_ENUMERATOR, /* enumerator (enumeration value) */
225 TAG_FIELD, /* field (Java) */
226 TAG_FUNCTION, /* function definition */
227 TAG_INTERFACE, /* interface declaration */
228 TAG_MEMBER, /* structure, class or interface member */
229 TAG_METHOD, /* method declaration */
230 TAG_NAMESPACE, /* namespace name */
231 TAG_PACKAGE, /* package name */
232 TAG_PROTOTYPE, /* function prototype or declaration */
233 TAG_STRUCT, /* structure name */
234 TAG_TYPEDEF, /* typedef name */
235 TAG_UNION, /* union name */
236 TAG_VARIABLE, /* variable definition */
237 TAG_EXTERN_VAR, /* external variable declaration */
238 TAG_MACRO, /* #define s */
239 TAG_EVENT, /* event */
240 TAG_SIGNAL, /* signal */
241 TAG_LOCAL, /* local variable definition */
242 TAG_PROPERTY, /* property name */
243 TAG_COUNT /* must be last */
244 } tagType;
246 typedef struct sParenInfo
248 boolean isParamList;
249 boolean isKnrParamList;
250 boolean isNameCandidate;
251 boolean invalidContents;
252 boolean nestedArgs;
253 unsigned int parameterCount;
254 } parenInfo;
257 * DATA DEFINITIONS
260 static jmp_buf Exception;
262 static langType Lang_c;
263 static langType Lang_cpp;
264 static langType Lang_csharp;
265 static langType Lang_java;
266 static langType Lang_d;
267 static langType Lang_glsl;
268 static langType Lang_ferite;
269 static langType Lang_vala;
271 /* Used to index into the CKinds table. */
272 typedef enum
274 CK_UNDEFINED = -1,
275 CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
276 CK_ENUMERATION, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
277 CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
278 CK_EXTERN_VARIABLE
279 } cKind;
281 static kindOption CKinds [] = {
282 { TRUE, 'c', "class", "classes"},
283 { TRUE, 'd', "macro", "macro definitions"},
284 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
285 { TRUE, 'f', "function", "function definitions"},
286 { TRUE, 'g', "enum", "enumeration names"},
287 { TRUE, 'm', "member", "class, struct, and union members"},
288 { TRUE, 'n', "namespace", "namespaces"},
289 { FALSE, 'p', "prototype", "function prototypes"},
290 { TRUE, 's', "struct", "structure names"},
291 { TRUE, 't', "typedef", "typedefs"},
292 { TRUE, 'u', "union", "union names"},
293 { TRUE, 'v', "variable", "variable definitions"},
294 { FALSE, 'x', "externvar", "external variable declarations"},
297 /* Used to index into the DKinds table. */
298 typedef enum
300 DK_UNDEFINED = -1,
301 DK_CLASS, DK_ENUMERATOR, DK_FUNCTION,
302 DK_ENUMERATION, DK_INTERFACE, DK_MEMBER, DK_NAMESPACE, DK_PROTOTYPE,
303 DK_STRUCT, DK_TYPEDEF, DK_UNION, DK_VARIABLE,
304 DK_EXTERN_VARIABLE
305 } dKind;
307 static kindOption DKinds [] = {
308 { TRUE, 'c', "class", "classes"},
309 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
310 { TRUE, 'f', "function", "function definitions"},
311 { TRUE, 'g', "enum", "enumeration names"},
312 { TRUE, 'i', "interface", "interfaces"},
313 { TRUE, 'm', "member", "class, struct, and union members"},
314 { TRUE, 'n', "namespace", "namespaces"},
315 { FALSE, 'p', "prototype", "function prototypes"},
316 { TRUE, 's', "struct", "structure names"},
317 { TRUE, 't', "typedef", "typedefs"},
318 { TRUE, 'u', "union", "union names"},
319 { TRUE, 'v', "variable", "variable definitions"},
320 { FALSE, 'x', "externvar", "external variable declarations"},
323 /* Used to index into the JavaKinds table. */
324 typedef enum
326 JK_UNDEFINED = -1,
327 JK_CLASS, JK_FIELD, JK_INTERFACE, JK_METHOD,
328 JK_PACKAGE
329 } javaKind;
331 static kindOption JavaKinds [] = {
332 { TRUE, 'c', "class", "classes"},
333 { TRUE, 'f', "field", "fields"},
334 { TRUE, 'i', "interface", "interfaces"},
335 { TRUE, 'm', "method", "methods"},
336 { TRUE, 'p', "package", "packages"},
339 typedef enum
341 CSK_UNDEFINED = -1,
342 CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
343 CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
344 CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
345 } csharpKind;
347 static kindOption CsharpKinds [] = {
348 { TRUE, 'c', "class", "classes"},
349 { TRUE, 'd', "macro", "macro definitions"},
350 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
351 { TRUE, 'E', "event", "events"},
352 { TRUE, 'f', "field", "fields"},
353 { TRUE, 'g', "enum", "enumeration names"},
354 { TRUE, 'i', "interface", "interfaces"},
355 { FALSE, 'l', "local", "local variables"},
356 { TRUE, 'm', "method", "methods"},
357 { TRUE, 'n', "namespace", "namespaces"},
358 { TRUE, 'p', "property", "properties"},
359 { TRUE, 's', "struct", "structure names"},
360 { TRUE, 't', "typedef", "typedefs"},
363 typedef enum {
364 VK_UNDEFINED = -1,
365 VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FIELD,
366 VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_METHOD,
367 VK_NAMESPACE, VK_PROPERTY, VK_SIGNAL, VK_STRUCT
368 } valaKind;
370 static kindOption ValaKinds [] = {
371 { TRUE, 'c', "class", "classes"},
372 { TRUE, 'd', "macro", "macro definitions"},
373 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
374 { TRUE, 'f', "field", "fields"},
375 { TRUE, 'g', "enum", "enumeration names"},
376 { TRUE, 'i', "interface", "interfaces"},
377 { FALSE, 'l', "local", "local variables"},
378 { TRUE, 'm', "method", "methods"},
379 { TRUE, 'n', "namespace", "namespaces"},
380 { TRUE, 'p', "property", "properties"},
381 { TRUE, 'S', "signal", "signals"},
382 { TRUE, 's', "struct", "structure names"},
385 static const keywordDesc KeywordTable [] = {
386 /* C++ */
387 /* ANSI C | C# Java */
388 /* | | | | Vera */
389 /* | | | | | Vala */
390 /* | | | | | | D */
391 /* keyword keyword ID | | | | | | | */
392 { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0, 0, 1 } },
393 { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0, 1, 1 } },
394 { "alias", KEYWORD_TYPEDEF, { 0, 0, 0, 0, 0, 0, 1 } }, /* handle like typedef */
395 { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
396 { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
397 { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1, 0, 0 } },
398 { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1, 0, 0 } },
399 { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1, 0, 0 } },
400 { "body", KEYWORD_BODY, { 0, 0, 0, 0, 0, 0, 1 } },
401 { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0, 0, 0 } },
402 { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0, 0, 1 } },
403 { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0, 1, 1 } },
404 { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0, 1, 1 } },
405 { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0, 1, 1 } },
406 { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1, 1, 1 } },
407 { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0, 1, 1 } },
408 { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1, 0, 0 } },
409 { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1, 0, 0 } },
410 { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1, 0, 0 } },
411 { "do", KEYWORD_DO, { 1, 1, 1, 1, 0, 1, 1 } },
412 { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0, 1, 1 } },
413 { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0, 1, 1 } },
414 { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0, 1, 1 } },
415 { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0, 1, 1 } },
416 { "else", KEYWORD_ELSE, { 1, 1, 0, 1, 0, 1, 1 } },
417 { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1, 1, 1 } },
418 { "errordomain", KEYWORD_ENUM, { 0, 0, 0, 0, 0, 1, 0 } }, /* errordomain behaves like enum */
419 { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1, 0, 0 } },
420 { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0, 0, 1 } },
421 { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1, 0, 0 } },
422 { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1, 1, 0 } },
423 { "extern", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* hack to ignore extern */
424 { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0, 0, 1 } },
425 { "finally", KEYWORD_FINALLY, { 0, 0, 0, 0, 0, 1, 1 } },
426 { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0, 1, 1 } },
427 { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0, 1, 1 } },
428 { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0, 0, 0 } },
429 { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1, 0, 1 } },
430 { "get", KEYWORD_GET, { 0, 0, 0, 0, 0, 1, 0 } },
431 { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0, 1, 1 } },
432 { "if", KEYWORD_IF, { 1, 1, 1, 1, 0, 1, 1 } },
433 { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0, 0, 0 } },
434 { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0, 0, 1 } },
435 { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0, 1, 0 } },
436 { "in", KEYWORD_IN, { 0, 0, 0, 0, 0, 0, 1 } },
437 { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1, 0, 1 } },
438 { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1, 0, 0 } },
439 { "int", KEYWORD_INT, { 1, 1, 1, 1, 0, 1, 1 } },
440 { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1, 0, 0 } },
441 { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1, 1, 1 } },
442 { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0, 0, 0 } },
443 { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1, 0, 0 } },
444 { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0, 1, 1 } },
445 { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
446 { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
447 { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
448 { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
449 { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0, 0, 0 } },
450 { "module", KEYWORD_MODULE, { 0, 0, 0, 0, 0, 0, 1 } },
451 { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0, 1, 0 } },
452 { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0, 0, 0 } },
453 { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0, 1, 1 } },
454 { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1, 0, 0 } },
455 { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0, 0, 0 } },
456 { "out", KEYWORD_OUT, { 0, 0, 0, 0, 0, 1, 1 } },
457 { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1, 0, 0 } },
458 { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0, 0, 0 } },
459 { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0, 1, 1 } },
460 { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0, 0, 1 } },
461 { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1, 0, 0 } },
462 { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1, 0, 0 } },
463 { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0, 1, 1 } },
464 { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1, 0, 0 } },
465 { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1, 1, 1 } },
466 { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1, 1, 1 } },
467 { "ref", KEYWORD_REF, { 0, 0, 0, 0, 0, 1, 1 } },
468 { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0, 0, 0 } },
469 { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0, 1, 1 } },
470 { "set", KEYWORD_SET, { 0, 0, 0, 0, 0, 1, 0 } },
471 { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1, 0, 0 } },
472 { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0, 1, 1 } },
473 { "signal", KEYWORD_SIGNAL, { 0, 0, 0, 0, 0, 1, 0 } },
474 { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0, 0, 0 } },
475 { "size_t", KEYWORD_SIZE_T, { 1, 1, 0, 0, 0, 1, 1 } },
476 { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
477 { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1, 1, 1 } },
478 { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1, 1, 0 } },
479 { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0, 1, 1 } },
480 { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0, 1, 1 } },
481 { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0, 0, 1 } },
482 { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1, 0, 0 } },
483 { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0, 0, 1 } },
484 { "this", KEYWORD_THIS, { 0, 0, 1, 1, 0, 1, 0 } }, /* 0 to allow D ctor tags */
485 { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0, 1, 1 } },
486 { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0, 1, 0 } },
487 { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
488 { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1, 0, 0 } },
489 { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0, 0, 0 } },
490 { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0, 1, 1 } },
491 { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1, 0, 1 } },
492 { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0, 0, 0 } },
493 { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0, 1, 1 } },
494 { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0, 1, 1 } },
495 { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0, 0, 1 } },
496 { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0, 0, 1 } },
497 { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0, 1, 1 } },
498 { "using", KEYWORD_USING, { 0, 1, 1, 0, 0, 1, 0 } },
499 { "version", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* hack to ignore version */
500 { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1, 1, 0 } },
501 { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1, 1, 1 } },
502 { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0, 0, 1 } },
503 { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0, 0, 1 } },
504 { "weak", KEYWORD_WEAK, { 0, 0, 0, 0, 0, 1, 0 } },
505 { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0, 1, 1 } }
510 * FUNCTION PROTOTYPES
512 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
513 static void copyToken (tokenInfo *const dest, const tokenInfo *const src);
514 static const char *getVarType (const statementInfo *const st);
517 * FUNCTION DEFINITIONS
520 /* Debugging functions added by Biswa */
521 #if defined(DEBUG_C) && DEBUG_C
522 static char *tokenTypeName[] = {
523 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
524 "package", "paren-name", "';'", "spec", "*", "[]", "count"
527 static char *tagScopeNames[] = {
528 "global", "static", "extern", "friend", "typedef", "count"};
530 static char *declTypeNames[] = {
531 "none", "base", "class", "enum", "function", "ignore", "interface",
532 "namespace", "nomangle", "package", "struct", "union", "count"};
534 static char *impTypeNames[] = {
535 "default", "abstract", "virtual", "pure-virtual", "count"};
537 void printToken(const tokenInfo *const token)
539 fprintf(stderr, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName[token->type],
540 token->keyword, vStringValue(token->name));
543 void printTagEntry(const tagEntryInfo *tag)
545 fprintf(stderr, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag->name,
546 tag->kindName, tag->extensionFields.implementation, tag->extensionFields.scope[1],
547 tag->extensionFields.varType);
550 void printStatement(const statementInfo *const statement)
552 int i;
553 statementInfo *st = (statementInfo *) statement;
554 while (NULL != st)
556 fprintf(stderr, "Statement Info:\n------------------------\n");
557 fprintf(stderr, "scope: %s, decl: %s, impl: %s\n", tagScopeNames[st->scope],
558 declTypeNames[st->declaration], impTypeNames[st->implementation]);
559 for (i=0; i < NumTokens; ++i)
561 fprintf(stderr, "Token %d %s: ", i, (i == st->tokenIndex)?"(current)":"");
562 printToken(st->token[i]);
564 fprintf(stderr, "Context: ");
565 printToken(st->context);
566 fprintf(stderr, "Block: ");
567 printToken(st->blockName);
568 fprintf(stderr, "Parent classes: %s\n", vStringValue(st->parentClasses));
569 fprintf(stderr, "First token: ");
570 printToken(st->firstToken);
571 if (NULL != st->parent)
572 fprintf(stderr, "Printing Parent:\n");
573 st = st->parent;
575 fprintf(stderr, "-----------------------------------------------\n");
577 #endif
579 extern boolean includingDefineTags (void)
581 if (isLanguage(Lang_c) ||
582 isLanguage(Lang_cpp) ||
583 isLanguage(Lang_csharp) ||
584 isLanguage(Lang_ferite) ||
585 isLanguage(Lang_glsl) ||
586 isLanguage(Lang_vala))
587 return CKinds [CK_DEFINE].enabled;
589 return FALSE;
593 * Token management
596 static void initToken (tokenInfo* const token)
598 token->type = TOKEN_NONE;
599 token->keyword = KEYWORD_NONE;
600 token->lineNumber = getSourceLineNumber();
601 if (useFile())
602 token->filePosition = getInputFilePosition();
603 else
604 token->bufferPosition = getInputBufferPosition();
605 vStringClear(token->name);
608 static void advanceToken (statementInfo* const st)
610 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
611 st->tokenIndex = 0;
612 else
613 ++st->tokenIndex;
614 initToken(st->token[st->tokenIndex]);
617 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
619 unsigned int tokenIndex;
620 unsigned int num = (unsigned int) NumTokens;
621 Assert(n < num);
622 tokenIndex = (st->tokenIndex + num - n) % num;
624 return st->token[tokenIndex];
627 static void setToken (statementInfo *const st, const tokenType type)
629 tokenInfo *token;
630 token = activeToken (st);
631 initToken(token);
632 token->type = type;
635 static void retardToken (statementInfo *const st)
637 if (st->tokenIndex == 0)
638 st->tokenIndex = (unsigned int) NumTokens - 1;
639 else
640 --st->tokenIndex;
641 setToken(st, TOKEN_NONE);
644 static tokenInfo *newToken (void)
646 tokenInfo *const token = xMalloc (1, tokenInfo);
647 token->name = vStringNew();
648 initToken(token);
649 return token;
652 static void deleteToken (tokenInfo *const token)
654 if (token != NULL)
656 vStringDelete(token->name);
657 eFree(token);
661 static const char *accessString (const accessType laccess)
663 static const char *const names [] ={
664 "?", "private", "protected", "public", "default"
666 Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
667 Assert ((int) laccess < ACCESS_COUNT);
668 return names[(int) laccess];
671 static const char *implementationString (const impType imp)
673 static const char *const names [] ={
674 "?", "abstract", "virtual", "pure virtual"
676 Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
677 Assert ((int) imp < IMP_COUNT);
678 return names [(int) imp];
682 * Debugging functions
685 #ifdef TM_DEBUG
687 #define boolString(c) ((c) ? "TRUE" : "FALSE")
689 static const char *tokenString (const tokenType type)
691 static const char *const names [] = {
692 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
693 "package", "paren-name", "semicolon", "specifier", "*", "[]", "count"
695 Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
696 Assert ((int) type < TOKEN_COUNT);
697 return names[(int) type];
700 static const char *scopeString (const tagScope scope)
702 static const char *const names [] = {
703 "global", "static", "extern", "friend", "typedef"
705 Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
706 Assert ((int) scope < SCOPE_COUNT);
707 return names[(int) scope];
710 static const char *declString (const declType declaration)
712 static const char *const names [] = {
713 "?", "base", "class", "enum", "function", "ignore", "interface",
714 "namespace", "no mangle", "package", "struct", "union",
716 Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
717 Assert ((int) declaration < DECL_COUNT);
718 return names[(int) declaration];
721 static const char *keywordString (const keywordId keyword)
723 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
724 const char *name = "none";
725 size_t i;
726 for (i = 0 ; i < count ; ++i)
728 const keywordDesc *p = &KeywordTable[i];
730 if (p->id == keyword)
732 name = p->name;
733 break;
736 return name;
739 static void __unused__ pt (tokenInfo *const token)
741 if (isType (token, TOKEN_NAME))
742 printf("type: %-12s: %-13s line: %lu\n",
743 tokenString (token->type), vStringValue (token->name),
744 token->lineNumber);
745 else if (isType (token, TOKEN_KEYWORD))
746 printf("type: %-12s: %-13s line: %lu\n",
747 tokenString (token->type), keywordString (token->keyword),
748 token->lineNumber);
749 else
750 printf("type: %-12s line: %lu\n",
751 tokenString (token->type), token->lineNumber);
754 static void __unused__ ps (statementInfo *const st)
756 unsigned int i;
757 printf("scope: %s decl: %s gotName: %s gotParenName: %s\n",
758 scopeString (st->scope), declString (st->declaration),
759 boolString (st->gotName), boolString (st->gotParenName));
760 printf("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
761 printf("access: %s default: %s\n", accessString (st->member.access),
762 accessString (st->member.accessDefault));
763 printf("token : ");
764 pt(activeToken (st));
765 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
767 printf("prev %u : ", i);
768 pt(prevToken (st, i));
770 printf("context: ");
771 pt(st->context);
774 #endif
777 * Statement management
780 static boolean isDataTypeKeyword (const tokenInfo *const token)
782 switch (token->keyword)
784 case KEYWORD_BOOLEAN:
785 case KEYWORD_BYTE:
786 case KEYWORD_CHAR:
787 case KEYWORD_DOUBLE:
788 case KEYWORD_FLOAT:
789 case KEYWORD_INT:
790 case KEYWORD_LONG:
791 case KEYWORD_SHORT:
792 case KEYWORD_VOID:
793 case KEYWORD_WCHAR_T:
794 case KEYWORD_SIZE_T:
795 return TRUE;
796 default:
797 return FALSE;
801 #if 0
802 static boolean isVariableKeyword (const tokenInfo *const token)
804 switch (token->keyword)
806 case KEYWORD_CONST:
807 case KEYWORD_EXTERN:
808 case KEYWORD_REGISTER:
809 case KEYWORD_STATIC:
810 case KEYWORD_VIRTUAL:
811 case KEYWORD_SIGNED:
812 case KEYWORD_UNSIGNED:
813 return TRUE;
814 default:
815 return FALSE;
818 #endif
820 static boolean isContextualKeyword (const tokenInfo *const token)
822 boolean result;
823 switch (token->keyword)
825 case KEYWORD_CLASS:
826 case KEYWORD_ENUM:
827 case KEYWORD_INTERFACE:
828 case KEYWORD_NAMESPACE:
829 case KEYWORD_STRUCT:
830 case KEYWORD_UNION:
832 result = TRUE;
833 break;
836 default:
838 result = FALSE;
839 break;
842 return result;
845 static boolean isContextualStatement (const statementInfo *const st)
847 boolean result = FALSE;
849 if (st != NULL)
851 if (isLanguage (Lang_vala))
853 /* All can be a contextual statment as properties can be of any type */
854 result = TRUE;
856 else
858 switch (st->declaration)
860 case DECL_CLASS:
861 case DECL_ENUM:
862 case DECL_INTERFACE:
863 case DECL_NAMESPACE:
864 case DECL_STRUCT:
865 case DECL_UNION:
867 result = TRUE;
868 break;
871 default:
873 result = FALSE;
874 break;
879 return result;
882 static boolean isMember (const statementInfo *const st)
884 boolean result;
885 if (isType (st->context, TOKEN_NAME))
886 result = TRUE;
887 else
888 result = isContextualStatement (st->parent);
889 return result;
892 static void initMemberInfo (statementInfo *const st)
894 accessType accessDefault = ACCESS_UNDEFINED;
896 if (st->parent != NULL) switch (st->parent->declaration)
898 case DECL_ENUM:
899 case DECL_NAMESPACE:
901 accessDefault = ACCESS_UNDEFINED;
902 break;
904 case DECL_CLASS:
906 if (isLanguage (Lang_java))
907 accessDefault = ACCESS_DEFAULT;
908 else
909 accessDefault = ACCESS_PRIVATE;
910 break;
912 case DECL_INTERFACE:
913 case DECL_STRUCT:
914 case DECL_UNION:
916 accessDefault = ACCESS_PUBLIC;
917 break;
919 default:
920 break;
922 st->member.accessDefault = accessDefault;
923 st->member.access = accessDefault;
926 static void reinitStatement (statementInfo *const st, const boolean partial)
928 unsigned int i;
930 if (! partial)
932 st->scope = SCOPE_GLOBAL;
933 if (isContextualStatement (st->parent))
934 st->declaration = DECL_BASE;
935 else
936 st->declaration = DECL_NONE;
938 st->gotParenName = FALSE;
939 st->implementation = IMP_DEFAULT;
940 st->gotArgs = FALSE;
941 st->gotName = FALSE;
942 st->haveQualifyingName = FALSE;
943 st->argEndPosition = 0;
945 st->tokenIndex = 0;
946 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
948 initToken (st->token [i]);
951 initToken (st->context);
952 initToken (st->blockName);
953 vStringClear (st->parentClasses);
955 /* Init member info.
957 if (! partial)
958 st->member.access = st->member.accessDefault;
960 /* Init first token */
961 if (!partial)
962 initToken(st->firstToken);
965 static void reinitStatementWithToken (statementInfo *const st,
966 tokenInfo *token, const boolean partial)
968 tokenInfo *const save = newToken ();
969 /* given token can be part of reinit statementInfo */
970 copyToken (save, token);
971 reinitStatement (st, partial);
972 token = activeToken (st);
973 copyToken (token, save);
974 deleteToken (save);
975 ++st->tokenIndex; /* this is quite save becouse current tokenIndex = 0 */
978 static void initStatement (statementInfo *const st, statementInfo *const parent)
980 st->parent = parent;
981 initMemberInfo (st);
982 reinitStatement (st, FALSE);
983 if(parent)
985 const tokenInfo *const src = activeToken (parent);
986 tokenInfo *const dst = activeToken (st);
987 copyToken (dst, src);
988 st->tokenIndex++;
993 * Tag generation functions
995 static cKind cTagKind (const tagType type)
997 cKind result = CK_UNDEFINED;
998 switch (type)
1000 case TAG_CLASS: result = CK_CLASS; break;
1001 case TAG_ENUM: result = CK_ENUMERATION; break;
1002 case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
1003 case TAG_FUNCTION: result = CK_FUNCTION; break;
1004 case TAG_MEMBER: result = CK_MEMBER; break;
1005 case TAG_NAMESPACE: result = CK_NAMESPACE; break;
1006 case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
1007 case TAG_STRUCT: result = CK_STRUCT; break;
1008 case TAG_TYPEDEF: result = CK_TYPEDEF; break;
1009 case TAG_UNION: result = CK_UNION; break;
1010 case TAG_VARIABLE: result = CK_VARIABLE; break;
1011 case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
1013 default: Assert ("Bad C tag type" == NULL); break;
1015 return result;
1018 static csharpKind csharpTagKind (const tagType type)
1020 csharpKind result = CSK_UNDEFINED;
1021 switch (type)
1023 case TAG_CLASS: result = CSK_CLASS; break;
1024 case TAG_ENUM: result = CSK_ENUMERATION; break;
1025 case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
1026 case TAG_EVENT: result = CSK_EVENT; break;
1027 case TAG_FIELD: result = CSK_FIELD ; break;
1028 case TAG_INTERFACE: result = CSK_INTERFACE; break;
1029 case TAG_LOCAL: result = CSK_LOCAL; break;
1030 case TAG_METHOD: result = CSK_METHOD; break;
1031 case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
1032 case TAG_PROPERTY: result = CSK_PROPERTY; break;
1033 case TAG_STRUCT: result = CSK_STRUCT; break;
1034 case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
1036 default: Assert ("Bad C# tag type" == NULL); break;
1038 return result;
1041 static dKind dTagKind (const tagType type)
1043 dKind result = DK_UNDEFINED;
1044 switch (type)
1046 case TAG_CLASS: result = DK_CLASS; break;
1047 case TAG_ENUM: result = DK_ENUMERATION; break;
1048 case TAG_ENUMERATOR: result = DK_ENUMERATOR; break;
1049 case TAG_FUNCTION: result = DK_FUNCTION; break;
1050 case TAG_INTERFACE: result = DK_INTERFACE; break;
1051 case TAG_MEMBER: result = DK_MEMBER; break;
1052 case TAG_NAMESPACE: result = DK_NAMESPACE; break;
1053 case TAG_PROTOTYPE: result = DK_PROTOTYPE; break;
1054 case TAG_STRUCT: result = DK_STRUCT; break;
1055 case TAG_TYPEDEF: result = DK_TYPEDEF; break;
1056 case TAG_UNION: result = DK_UNION; break;
1057 case TAG_VARIABLE: result = DK_VARIABLE; break;
1058 case TAG_EXTERN_VAR: result = DK_EXTERN_VARIABLE; break;
1060 default: Assert ("Bad D tag type" == NULL); break;
1062 return result;
1065 static valaKind valaTagKind (const tagType type)
1067 valaKind result = VK_UNDEFINED;
1068 switch (type)
1070 case TAG_CLASS: result = VK_CLASS; break;
1071 case TAG_ENUM: result = VK_ENUMERATION; break;
1072 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
1073 case TAG_SIGNAL: result = VK_SIGNAL; break;
1074 case TAG_FIELD: result = VK_FIELD ; break;
1075 case TAG_INTERFACE: result = VK_INTERFACE; break;
1076 case TAG_LOCAL: result = VK_LOCAL; break;
1077 case TAG_METHOD: result = VK_METHOD; break;
1078 case TAG_NAMESPACE: result = VK_NAMESPACE; break;
1079 case TAG_PROPERTY: result = VK_PROPERTY; break;
1080 case TAG_STRUCT: result = VK_STRUCT; break;
1082 default: Assert ("Bad Vala tag type" == NULL); break;
1084 return result;
1087 static javaKind javaTagKind (const tagType type)
1089 javaKind result = JK_UNDEFINED;
1090 switch (type)
1092 case TAG_CLASS: result = JK_CLASS; break;
1093 case TAG_FIELD: result = JK_FIELD; break;
1094 case TAG_INTERFACE: result = JK_INTERFACE; break;
1095 case TAG_METHOD: result = JK_METHOD; break;
1096 case TAG_PACKAGE: result = JK_PACKAGE; break;
1098 default: Assert ("Bad Java tag type" == NULL); break;
1100 return result;
1103 static const char *tagName (const tagType type)
1105 const char* result;
1106 if (isLanguage (Lang_java))
1107 result = JavaKinds [javaTagKind (type)].name;
1108 else if (isLanguage (Lang_csharp))
1109 result = CsharpKinds [csharpTagKind (type)].name;
1110 else if (isLanguage (Lang_d))
1111 result = DKinds [dTagKind (type)].name;
1112 else if (isLanguage (Lang_vala))
1113 result = ValaKinds [valaTagKind (type)].name;
1114 else
1115 result = CKinds [cTagKind (type)].name;
1116 return result;
1119 static int tagLetter (const tagType type)
1121 int result;
1122 if (isLanguage (Lang_csharp))
1123 result = CsharpKinds [csharpTagKind (type)].letter;
1124 else if (isLanguage (Lang_d))
1125 result = DKinds [dTagKind (type)].letter;
1126 else if (isLanguage (Lang_java))
1127 result = JavaKinds [javaTagKind (type)].letter;
1128 else if (isLanguage (Lang_vala))
1129 result = ValaKinds [valaTagKind (type)].letter;
1130 else
1131 result = CKinds [cTagKind (type)].letter;
1132 return result;
1136 static boolean includeTag (const tagType type, const boolean isFileScope)
1138 boolean result;
1139 if (isFileScope && ! Option.include.fileScope)
1140 result = FALSE;
1141 else if (isLanguage (Lang_java))
1142 result = JavaKinds [javaTagKind (type)].enabled;
1143 else
1144 result = CKinds [cTagKind (type)].enabled;
1145 return result;
1149 static tagType declToTagType (const declType declaration)
1151 tagType type = TAG_UNDEFINED;
1153 switch (declaration)
1155 case DECL_CLASS: type = TAG_CLASS; break;
1156 case DECL_ENUM: type = TAG_ENUM; break;
1157 case DECL_FUNCTION: type = TAG_FUNCTION; break;
1158 case DECL_INTERFACE:type = TAG_INTERFACE; break;
1159 case DECL_NAMESPACE:type = TAG_NAMESPACE; break;
1160 case DECL_STRUCT: type = TAG_STRUCT; break;
1161 case DECL_UNION: type = TAG_UNION; break;
1163 default: Assert ("Unexpected declaration" == NULL); break;
1165 return type;
1168 static const char* accessField (const statementInfo *const st)
1170 const char* result = NULL;
1172 if ((isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite)) &&
1173 st->scope == SCOPE_FRIEND)
1174 result = "friend";
1175 else if (st->member.access != ACCESS_UNDEFINED)
1176 result = accessString (st->member.access);
1177 return result;
1180 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
1181 const statementInfo *const st, vString *const scope)
1183 /* For selected tag types, append an extension flag designating the
1184 * parent object in which the tag is defined.
1186 switch (type)
1188 default: break;
1190 case TAG_CLASS:
1191 case TAG_ENUM:
1192 case TAG_ENUMERATOR:
1193 case TAG_FIELD:
1194 case TAG_FUNCTION:
1195 case TAG_INTERFACE:
1196 case TAG_MEMBER:
1197 case TAG_METHOD:
1198 case TAG_PROTOTYPE:
1199 case TAG_STRUCT:
1200 case TAG_TYPEDEF:
1201 case TAG_UNION:
1203 if (vStringLength (scope) > 0 &&
1204 (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1206 if (isType (st->context, TOKEN_NAME))
1207 tag->extensionFields.scope [0] = tagName (TAG_CLASS);
1208 else
1209 tag->extensionFields.scope [0] =
1210 tagName (declToTagType (parentDecl (st)));
1211 tag->extensionFields.scope [1] = vStringValue (scope);
1213 if ((type == TAG_CLASS || type == TAG_INTERFACE ||
1214 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
1217 tag->extensionFields.inheritance =
1218 vStringValue (st->parentClasses);
1220 if (st->implementation != IMP_DEFAULT &&
1221 (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
1222 isLanguage (Lang_java) || isLanguage (Lang_d) || isLanguage (Lang_ferite)))
1224 tag->extensionFields.implementation =
1225 implementationString (st->implementation);
1227 if (isMember (st))
1229 tag->extensionFields.access = accessField (st);
1231 if ((TRUE == st->gotArgs) && (TRUE == Option.extensionFields.argList) &&
1232 ((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type)))
1234 if (useFile())
1236 tag->extensionFields.arglist = getArglistFromFilePos(
1237 tag->filePosition, tag->name);
1239 else
1241 tag->extensionFields.arglist = getArglistFromBufferPos(
1242 tag->bufferPosition, tag->name);
1245 break;
1249 if ((TAG_FIELD == tag->type) || (TAG_MEMBER == tag->type) ||
1250 (TAG_EXTERN_VAR == tag->type) || (TAG_TYPEDEF == tag->type) ||
1251 (TAG_VARIABLE == tag->type) || (TAG_METHOD == tag->type) ||
1252 (TAG_PROTOTYPE == tag->type) || (TAG_FUNCTION == tag->type))
1254 if (((TOKEN_NAME == st->firstToken->type) || isDataTypeKeyword(st->firstToken))
1255 && (0 != strcmp(vStringValue(st->firstToken->name), tag->name)))
1257 tag->extensionFields.varType = getVarType(st);
1262 static const char *getVarType (const statementInfo *const st)
1264 static vString *vt = NULL;
1265 unsigned int i;
1267 if (! st->gotArgs)
1268 return vStringValue(st->firstToken->name); /* ignore non-functions */
1270 if (vt == NULL)
1271 vt = vStringNew();
1272 else
1273 vStringClear(vt);
1275 for (i = 0; i < st->tokenIndex; i++)
1277 tokenInfo *t = st->token[i];
1279 switch (t->type)
1281 case TOKEN_NAME: /* user typename */
1282 if (strcmp(vStringValue(t->name), vStringValue(st->firstToken->name)) != 0)
1283 continue;
1284 break;
1285 case TOKEN_KEYWORD:
1286 if (t->keyword != KEYWORD_EXTERN && t->keyword != KEYWORD_STATIC) /* uninteresting keywords */
1287 break;
1288 continue;
1289 case TOKEN_STAR: vStringCatS(vt, " *"); continue;
1290 case TOKEN_ARRAY: vStringCatS(vt, "[]"); continue;
1291 default: continue;
1293 if (vStringLength(vt) > 0)
1294 if (isalpha(vStringValue(vt)[vStringLength(vt) - 1]))
1295 vStringPut(vt, ' ');
1296 vStringCat(vt, t->name);
1298 vStringTerminate(vt);
1299 return vStringValue(vt);
1302 static void addContextSeparator (vString *const scope)
1304 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
1305 vStringCatS (scope, "::");
1306 else if (isLanguage (Lang_java) || isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
1307 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1308 vStringCatS (scope, ".");
1311 static void findScopeHierarchy (vString *const string,
1312 const statementInfo *const st)
1314 const char* const anon = "<anonymous>";
1315 boolean nonAnonPresent = FALSE;
1317 vStringClear (string);
1318 if (isType (st->context, TOKEN_NAME))
1320 vStringCopy (string, st->context->name);
1321 nonAnonPresent = TRUE;
1323 if (st->parent != NULL)
1325 vString *temp = vStringNew ();
1326 const statementInfo *s;
1328 for (s = st->parent ; s != NULL ; s = s->parent)
1330 if (isContextualStatement (s) ||
1331 s->declaration == DECL_NAMESPACE)
1333 vStringCopy (temp, string);
1334 vStringClear (string);
1335 if (isType (s->blockName, TOKEN_NAME))
1337 if (isType (s->context, TOKEN_NAME) &&
1338 vStringLength (s->context->name) > 0)
1340 vStringCat (string, s->context->name);
1341 addContextSeparator (string);
1343 vStringCat (string, s->blockName->name);
1344 nonAnonPresent = TRUE;
1346 else
1347 vStringCopyS (string, anon);
1348 if (vStringLength (temp) > 0)
1349 addContextSeparator (string);
1350 vStringCat (string, temp);
1353 vStringDelete (temp);
1355 if (! nonAnonPresent)
1356 vStringClear (string);
1360 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1361 vString *const scope)
1363 if (Option.include.qualifiedTags &&
1364 scope != NULL && vStringLength (scope) > 0)
1366 vString *const scopedName = vStringNew ();
1368 if (type != TAG_ENUMERATOR)
1369 vStringCopy (scopedName, scope);
1370 else
1372 /* remove last component (i.e. enumeration name) from scope */
1373 const char* const sc = vStringValue (scope);
1374 const char* colon = strrchr (sc, ':');
1375 if (colon != NULL)
1377 while (*colon == ':' && colon > sc)
1378 --colon;
1379 vStringNCopy (scopedName, scope, colon + 1 - sc);
1382 if (vStringLength (scopedName) > 0)
1384 addContextSeparator (scopedName);
1385 vStringCatS (scopedName, e->name);
1386 e->name = vStringValue (scopedName);
1387 makeTagEntry (e);
1389 vStringDelete (scopedName);
1393 static void makeTag (const tokenInfo *const token,
1394 const statementInfo *const st,
1395 boolean isFileScope, const tagType type)
1397 #ifdef DEBUG_C
1398 printToken(token);
1399 fprintf(stderr, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
1400 printStatement(st);
1401 #endif
1402 /* Nothing is really of file scope when it appears in a header file.
1404 isFileScope = (boolean) (isFileScope && ! isHeaderFile ());
1406 if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 /* &&
1407 includeTag (type, isFileScope) */)
1409 vString *scope = vStringNew ();
1410 tagEntryInfo e;
1412 /* take only functions which are introduced by "function ..." */
1413 if (type == TAG_FUNCTION && isLanguage (Lang_ferite) &&
1414 strncmp("function", st->firstToken->name->buffer, 8) != 0)
1416 return;
1419 initTagEntry (&e, vStringValue (token->name));
1421 e.lineNumber = token->lineNumber;
1422 if (useFile())
1423 e.filePosition = token->filePosition;
1424 else
1425 e.bufferPosition = token->bufferPosition;
1426 e.isFileScope = isFileScope;
1427 e.kindName = tagName (type);
1428 e.kind = tagLetter (type);
1429 e.type = type;
1431 findScopeHierarchy (scope, st);
1432 addOtherFields (&e, type, st, scope);
1434 #ifdef DEBUG_C
1435 printTagEntry(&e);
1436 #endif
1437 makeTagEntry (&e);
1438 if (NULL != TagEntryFunction)
1439 makeExtraTagEntry (type, &e, scope);
1440 vStringDelete (scope);
1441 if (NULL != e.extensionFields.arglist)
1442 free((char *) e.extensionFields.arglist);
1446 static boolean isValidTypeSpecifier (const declType declaration)
1448 boolean result;
1449 switch (declaration)
1451 case DECL_BASE:
1452 case DECL_CLASS:
1453 case DECL_ENUM:
1454 case DECL_STRUCT:
1455 case DECL_UNION:
1456 result = TRUE;
1457 break;
1459 default:
1460 result = FALSE;
1461 break;
1463 return result;
1466 static void qualifyEnumeratorTag (const statementInfo *const st,
1467 const tokenInfo *const nameToken)
1469 if (isType (nameToken, TOKEN_NAME))
1470 makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
1473 static void qualifyFunctionTag (const statementInfo *const st,
1474 const tokenInfo *const nameToken)
1476 if (isType (nameToken, TOKEN_NAME))
1478 const tagType type = (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1479 ? TAG_METHOD : TAG_FUNCTION;
1480 const boolean isFileScope =
1481 (boolean) (st->member.access == ACCESS_PRIVATE ||
1482 (!isMember (st) && st->scope == SCOPE_STATIC));
1484 makeTag (nameToken, st, isFileScope, type);
1488 static void qualifyFunctionDeclTag (const statementInfo *const st,
1489 const tokenInfo *const nameToken)
1491 if (! isType (nameToken, TOKEN_NAME))
1493 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1494 qualifyFunctionTag (st, nameToken);
1495 else if (st->scope == SCOPE_TYPEDEF)
1496 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1497 else if (isValidTypeSpecifier (st->declaration) &&
1498 ! (isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1499 makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
1502 static void qualifyCompoundTag (const statementInfo *const st,
1503 const tokenInfo *const nameToken)
1505 if (isType (nameToken, TOKEN_NAME))
1507 const tagType type = declToTagType (st->declaration);
1509 if (type != TAG_UNDEFINED)
1510 makeTag (nameToken, st, (boolean) (! isLanguage (Lang_java) &&
1511 ! isLanguage (Lang_csharp) &&
1512 ! isLanguage (Lang_vala)), type);
1516 static void qualifyBlockTag (statementInfo *const st,
1517 const tokenInfo *const nameToken)
1519 switch (st->declaration)
1521 case DECL_CLASS:
1522 case DECL_ENUM:
1523 case DECL_INTERFACE:
1524 case DECL_NAMESPACE:
1525 case DECL_STRUCT:
1526 case DECL_UNION:
1527 qualifyCompoundTag (st, nameToken);
1528 break;
1529 default: break;
1533 static void qualifyVariableTag (const statementInfo *const st,
1534 const tokenInfo *const nameToken)
1536 /* We have to watch that we do not interpret a declaration of the
1537 * form "struct tag;" as a variable definition. In such a case, the
1538 * token preceding the name will be a keyword.
1540 if (! isType (nameToken, TOKEN_NAME))
1542 else if (st->declaration == DECL_IGNORE)
1544 else if (st->scope == SCOPE_TYPEDEF)
1545 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1546 else if (st->declaration == DECL_PACKAGE)
1547 makeTag (nameToken, st, FALSE, TAG_PACKAGE);
1548 else if (st->declaration == DECL_MODULE) /* handle modules in D as namespaces */
1549 makeTag (nameToken, st, FALSE, TAG_NAMESPACE);
1550 else if (isValidTypeSpecifier (st->declaration))
1552 if (isMember (st))
1554 if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
1555 makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1556 else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1557 makeTag (nameToken, st, TRUE, TAG_MEMBER);
1559 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala));
1560 else
1562 if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1563 makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
1564 else
1565 makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC), TAG_VARIABLE);
1571 * Parsing functions
1574 static int skipToOneOf (const char *const chars)
1576 int c;
1578 c = cppGetc ();
1579 while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1581 return c;
1584 /* Skip to the next non-white character.
1586 static int skipToNonWhite (void)
1588 int c;
1592 c = cppGetc ();
1594 while (isspace (c));
1596 return c;
1599 /* Skips to the next brace in column 1. This is intended for cases where
1600 * preprocessor constructs result in unbalanced braces.
1602 static void skipToFormattedBraceMatch (void)
1604 int c, next;
1606 c = cppGetc ();
1607 next = cppGetc ();
1608 while (c != EOF && (c != '\n' || next != '}'))
1610 c = next;
1611 next = cppGetc ();
1615 /* Skip to the matching character indicated by the pair string. If skipping
1616 * to a matching brace and any brace is found within a different level of a
1617 * #if conditional statement while brace formatting is in effect, we skip to
1618 * the brace matched by its formatting. It is assumed that we have already
1619 * read the character which starts the group (i.e. the first character of
1620 * "pair").
1622 static void skipToMatch (const char *const pair)
1624 const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
1625 const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
1626 const unsigned int initialLevel = getDirectiveNestLevel ();
1627 const int begin = pair [0], end = pair [1];
1628 const unsigned long inputLineNumber = getInputLineNumber ();
1629 int matchLevel = 1;
1630 int c = '\0';
1631 while (matchLevel > 0 && (c = cppGetc ()) != EOF)
1633 if (c == begin)
1635 ++matchLevel;
1636 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1638 skipToFormattedBraceMatch ();
1639 break;
1642 else if (c == end)
1644 --matchLevel;
1645 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1647 skipToFormattedBraceMatch ();
1648 break;
1652 if (c == EOF)
1654 verbose ("%s: failed to find match for '%c' at line %lu\n",
1655 getInputFileName (), begin, inputLineNumber);
1656 if (braceMatching)
1657 longjmp (Exception, (int) ExceptionBraceFormattingError);
1658 else
1659 longjmp (Exception, (int) ExceptionFormattingError);
1663 static void skipParens (void)
1665 const int c = skipToNonWhite ();
1667 if (c == '(')
1668 skipToMatch ("()");
1669 else
1670 cppUngetc (c);
1673 static void skipBraces (void)
1675 const int c = skipToNonWhite ();
1677 if (c == '{')
1678 skipToMatch ("{}");
1679 else
1680 cppUngetc (c);
1683 static keywordId analyzeKeyword (const char *const name)
1685 const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1686 return id;
1689 static void analyzeIdentifier (tokenInfo *const token)
1691 char *const name = vStringValue (token->name);
1692 const char *replacement = NULL;
1693 boolean parensToo = FALSE;
1695 if (isLanguage (Lang_java) ||
1696 ! isIgnoreToken (name, &parensToo, &replacement))
1698 if (replacement != NULL)
1699 token->keyword = analyzeKeyword (replacement);
1700 else
1701 token->keyword = analyzeKeyword (vStringValue (token->name));
1703 if (token->keyword == KEYWORD_NONE)
1704 token->type = TOKEN_NAME;
1705 else
1706 token->type = TOKEN_KEYWORD;
1708 else
1710 initToken (token);
1711 if (parensToo)
1713 int c = skipToNonWhite ();
1715 if (c == '(')
1716 skipToMatch ("()");
1721 static void readIdentifier (tokenInfo *const token, const int firstChar)
1723 vString *const name = token->name;
1724 int c = firstChar;
1726 initToken (token);
1728 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1729 * the ~ and the class name. */
1730 if (isLanguage (Lang_cpp) && firstChar == '~')
1732 vStringPut (name, c);
1733 c = skipToNonWhite ();
1738 vStringPut (name, c);
1739 c = cppGetc ();
1740 } while (isident (c) || (isLanguage (Lang_vala) && '.' == c));
1741 vStringTerminate (name);
1742 cppUngetc (c); /* unget non-identifier character */
1744 /* Vala supports '?' at end of a type (with or without whitspace before) for nullable types */
1745 if (isLanguage (Lang_vala))
1747 c = skipToNonWhite ();
1748 if ('?' == c)
1749 vStringPut (name, c);
1750 else
1751 cppUngetc (c);
1754 analyzeIdentifier (token);
1757 static void readPackageName (tokenInfo *const token, const int firstChar)
1759 vString *const name = token->name;
1760 int c = firstChar;
1762 initToken (token);
1764 while (isident (c) || c == '.')
1766 vStringPut (name, c);
1767 c = cppGetc ();
1769 vStringTerminate (name);
1770 cppUngetc (c); /* unget non-package character */
1773 static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1775 st->declaration = declaration;
1777 if (declaration == DECL_NAMESPACE && !(isLanguage (Lang_csharp) || isLanguage (Lang_vala)))
1779 /* In C++ a namespace is specified one level at a time. */
1780 return;
1782 else
1784 /* In C#, a namespace can also be specified like a Java package name. */
1785 tokenInfo *const token = activeToken (st);
1786 Assert (isType (token, TOKEN_KEYWORD));
1787 readPackageName (token, skipToNonWhite ());
1788 token->type = TOKEN_NAME;
1789 st->gotName = TRUE;
1790 st->haveQualifyingName = TRUE;
1794 static void readPackage (statementInfo *const st)
1796 tokenInfo *const token = activeToken (st);
1797 Assert (isType (token, TOKEN_KEYWORD));
1798 readPackageName (token, skipToNonWhite ());
1799 token->type = TOKEN_NAME;
1800 if (isLanguage (Lang_d))
1801 st->declaration = DECL_MODULE;
1802 else
1803 st->declaration = DECL_PACKAGE;
1804 st->gotName = TRUE;
1805 st->haveQualifyingName = TRUE;
1808 static void processName (statementInfo *const st)
1810 Assert (isType (activeToken (st), TOKEN_NAME));
1811 if (st->gotName && st->declaration == DECL_NONE)
1812 st->declaration = DECL_BASE;
1813 st->gotName = TRUE;
1814 st->haveQualifyingName = TRUE;
1817 static void readOperator (statementInfo *const st)
1819 const char *const acceptable = "+-*/%^&|~!=<>,[]";
1820 const tokenInfo* const prev = prevToken (st,1);
1821 tokenInfo *const token = activeToken (st);
1822 vString *const name = token->name;
1823 int c = skipToNonWhite ();
1825 /* When we arrive here, we have the keyword "operator" in 'name'.
1827 if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1828 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1829 ; /* ignore "operator" keyword if preceded by these keywords */
1830 else if (c == '(')
1832 /* Verify whether this is a valid function call (i.e. "()") operator.
1834 if (cppGetc () == ')')
1836 vStringPut (name, ' '); /* always separate operator from keyword */
1837 c = skipToNonWhite ();
1838 if (c == '(')
1839 vStringCatS (name, "()");
1841 else
1843 skipToMatch ("()");
1844 c = cppGetc ();
1847 else if (isident1 (c))
1849 /* Handle "new" and "delete" operators, and conversion functions
1850 * (per 13.3.1.1.2 [2] of the C++ spec).
1852 boolean whiteSpace = TRUE; /* default causes insertion of space */
1855 if (isspace (c))
1856 whiteSpace = TRUE;
1857 else
1859 if (whiteSpace)
1861 vStringPut (name, ' ');
1862 whiteSpace = FALSE;
1864 vStringPut (name, c);
1866 c = cppGetc ();
1867 } while (! isOneOf (c, "(;") && c != EOF);
1868 vStringTerminate (name);
1870 else if (isOneOf (c, acceptable))
1872 vStringPut (name, ' '); /* always separate operator from keyword */
1875 vStringPut (name, c);
1876 c = cppGetc ();
1877 } while (isOneOf (c, acceptable));
1878 vStringTerminate (name);
1881 cppUngetc (c);
1883 token->type = TOKEN_NAME;
1884 token->keyword = KEYWORD_NONE;
1885 processName (st);
1888 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1890 dest->type = src->type;
1891 dest->keyword = src->keyword;
1892 if (useFile())
1893 dest->filePosition = src->filePosition;
1894 else
1895 dest->bufferPosition = src->bufferPosition;
1896 dest->lineNumber = src->lineNumber;
1897 vStringCopy (dest->name, src->name);
1900 static void setAccess (statementInfo *const st, const accessType laccess)
1902 if (isMember (st))
1904 if (isLanguage (Lang_cpp) || isLanguage (Lang_d) || isLanguage (Lang_ferite))
1906 int c = skipToNonWhite ();
1908 if (c == ':')
1909 reinitStatementWithToken (st, prevToken (st, 1), FALSE);
1910 else
1911 cppUngetc (c);
1913 st->member.accessDefault = laccess;
1915 st->member.access = laccess;
1919 static void discardTypeList (tokenInfo *const token)
1921 int c = skipToNonWhite ();
1922 while (isident1 (c))
1924 readIdentifier (token, c);
1925 c = skipToNonWhite ();
1926 if (c == '.' || c == ',')
1927 c = skipToNonWhite ();
1929 cppUngetc (c);
1932 static void addParentClass (statementInfo *const st, tokenInfo *const token)
1934 if (vStringLength (token->name) > 0 &&
1935 vStringLength (st->parentClasses) > 0)
1937 vStringPut (st->parentClasses, ',');
1939 vStringCat (st->parentClasses, token->name);
1942 static void readParents (statementInfo *const st, const int qualifier)
1944 tokenInfo *const token = newToken ();
1945 tokenInfo *const parent = newToken ();
1946 int c;
1950 c = skipToNonWhite ();
1951 if (isident1 (c))
1953 readIdentifier (token, c);
1954 if (isType (token, TOKEN_NAME))
1955 vStringCat (parent->name, token->name);
1956 else
1958 addParentClass (st, parent);
1959 initToken (parent);
1962 else if (c == qualifier)
1963 vStringPut (parent->name, c);
1964 else if (c == '<')
1965 skipToMatch ("<>");
1966 else if (isType (token, TOKEN_NAME))
1968 addParentClass (st, parent);
1969 initToken (parent);
1971 } while (c != '{' && c != EOF);
1972 cppUngetc (c);
1973 deleteToken (parent);
1974 deleteToken (token);
1977 static void processToken (tokenInfo *const token, statementInfo *const st)
1979 switch (token->keyword) /* is it a reserved word? */
1981 default: break;
1983 case KEYWORD_NONE: processName (st); break;
1984 case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
1985 case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
1986 case KEYWORD_CATCH: skipParens (); skipBraces (); break;
1987 case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
1988 case KEYWORD_CLASS: st->declaration = DECL_CLASS; break;
1989 case KEYWORD_CONST: st->declaration = DECL_BASE; break;
1990 case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
1991 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
1992 case KEYWORD_EXTENDS: readParents (st, '.');
1993 setToken (st, TOKEN_NONE); break;
1994 case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
1995 case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
1996 case KEYWORD_IMPLEMENTS:readParents (st, '.');
1997 setToken (st, TOKEN_NONE); break;
1998 case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
1999 case KEYWORD_INT: st->declaration = DECL_BASE; break;
2000 case KEYWORD_BOOLEAN: st->declaration = DECL_BASE; break;
2001 case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
2002 case KEYWORD_SIZE_T: st->declaration = DECL_BASE; break;
2003 case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
2004 case KEYWORD_LONG: st->declaration = DECL_BASE; break;
2005 case KEYWORD_OPERATOR: readOperator (st); break;
2006 case KEYWORD_MODULE: readPackage (st); break;
2007 case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
2008 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
2009 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
2010 case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
2011 case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
2012 case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break;
2013 case KEYWORD_THROWS: discardTypeList (token); break;
2014 case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
2015 case KEYWORD_UNION: st->declaration = DECL_UNION; break;
2016 case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
2017 case KEYWORD_USING: st->declaration = DECL_IGNORE; break;
2018 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
2019 case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
2020 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
2022 case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
2023 case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
2024 case KEYWORD_EVENT:
2026 if (isLanguage (Lang_csharp))
2027 st->declaration = DECL_EVENT;
2028 break;
2030 case KEYWORD_SIGNAL:
2032 if (isLanguage (Lang_vala))
2033 st->declaration = DECL_SIGNAL;
2034 break;
2036 case KEYWORD_EXTERN:
2038 if (! isLanguage (Lang_csharp) || !st->gotName)
2040 /*reinitStatement (st, FALSE);*/
2041 st->scope = SCOPE_EXTERN;
2042 st->declaration = DECL_BASE;
2044 break;
2046 case KEYWORD_STATIC:
2048 if (! isLanguage (Lang_java) && ! isLanguage (Lang_csharp) && ! isLanguage (Lang_vala))
2050 /*reinitStatement (st, FALSE);*/
2051 st->scope = SCOPE_STATIC;
2052 st->declaration = DECL_BASE;
2054 break;
2060 * Parenthesis handling functions
2063 static void restartStatement (statementInfo *const st)
2065 tokenInfo *const save = newToken ();
2066 tokenInfo *token = activeToken (st);
2068 copyToken (save, token);
2069 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
2070 reinitStatement (st, FALSE);
2071 token = activeToken (st);
2072 copyToken (token, save);
2073 deleteToken (save);
2074 processToken (token, st);
2077 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
2079 * mem-initializer-list:
2080 * mem-initializer, mem-initializer-list
2082 * mem-initializer:
2083 * [::] [nested-name-spec] class-name (...)
2084 * identifier
2086 static void skipMemIntializerList (tokenInfo *const token)
2088 int c;
2092 c = skipToNonWhite ();
2093 while (isident1 (c) || c == ':')
2095 if (c != ':')
2096 readIdentifier (token, c);
2097 c = skipToNonWhite ();
2099 if (c == '<')
2101 skipToMatch ("<>");
2102 c = skipToNonWhite ();
2104 if (c == '(')
2106 skipToMatch ("()");
2107 c = skipToNonWhite ();
2109 } while (c == ',');
2110 cppUngetc (c);
2113 static void skipMacro (statementInfo *const st)
2115 tokenInfo *const prev2 = prevToken (st, 2);
2117 if (isType (prev2, TOKEN_NAME))
2118 retardToken (st);
2119 skipToMatch ("()");
2122 /* Skips over characters following the parameter list. This will be either
2123 * non-ANSI style function declarations or C++ stuff. Our choices:
2125 * C (K&R):
2126 * int func ();
2127 * int func (one, two) int one; float two; {...}
2128 * C (ANSI):
2129 * int func (int one, float two);
2130 * int func (int one, float two) {...}
2131 * C++:
2132 * int foo (...) [const|volatile] [throw (...)];
2133 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2134 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2135 * catch (...) {...}
2137 static boolean skipPostArgumentStuff (statementInfo *const st,
2138 parenInfo *const info)
2140 tokenInfo *const token = activeToken (st);
2141 unsigned int parameters = info->parameterCount;
2142 unsigned int elementCount = 0;
2143 boolean restart = FALSE;
2144 boolean end = FALSE;
2145 int c = skipToNonWhite ();
2149 switch (c)
2151 case ')': break;
2152 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
2153 case '[': skipToMatch ("[]"); break;
2154 case '=': cppUngetc (c); end = TRUE; break;
2155 case '{': cppUngetc (c); end = TRUE; break;
2156 case '}': cppUngetc (c); end = TRUE; break;
2158 case '(':
2160 if (elementCount > 0)
2161 ++elementCount;
2162 skipToMatch ("()");
2163 break;
2166 case ';':
2168 if (parameters == 0 || elementCount < 2)
2170 cppUngetc (c);
2171 end = TRUE;
2173 else if (--parameters == 0)
2174 end = TRUE;
2175 break;
2178 default:
2180 if (isident1 (c))
2182 readIdentifier (token, c);
2183 if (isLanguage(Lang_d))
2184 { /* parse D contracts */
2185 switch (token->keyword)
2187 case KEYWORD_IN:
2188 case KEYWORD_OUT:
2189 case KEYWORD_BODY:
2190 token->keyword = KEYWORD_CONST;
2191 default:
2192 break;
2195 switch (token->keyword)
2197 case KEYWORD_ATTRIBUTE: skipParens (); break;
2198 case KEYWORD_THROW: skipParens (); break;
2199 case KEYWORD_CONST: break;
2200 case KEYWORD_TRY: break;
2201 case KEYWORD_VOLATILE: break;
2203 case KEYWORD_CATCH: case KEYWORD_CLASS:
2204 case KEYWORD_EXPLICIT: case KEYWORD_EXTERN:
2205 case KEYWORD_FRIEND: case KEYWORD_INLINE:
2206 case KEYWORD_MUTABLE: case KEYWORD_NAMESPACE:
2207 case KEYWORD_NEW: case KEYWORD_OPERATOR:
2208 case KEYWORD_OVERLOAD: case KEYWORD_PRIVATE:
2209 case KEYWORD_PROTECTED: case KEYWORD_PUBLIC:
2210 case KEYWORD_STATIC: case KEYWORD_TEMPLATE:
2211 case KEYWORD_TYPEDEF: case KEYWORD_TYPENAME:
2212 case KEYWORD_USING: case KEYWORD_VIRTUAL:
2213 /* Never allowed within parameter declarations.
2215 restart = TRUE;
2216 end = TRUE;
2217 break;
2219 default:
2220 if (isType (token, TOKEN_NONE))
2222 else if (info->isKnrParamList && info->parameterCount > 0)
2223 ++elementCount;
2224 else
2226 /* If we encounter any other identifier immediately
2227 * following an empty parameter list, this is almost
2228 * certainly one of those Microsoft macro "thingies"
2229 * that the automatic source code generation sticks
2230 * in. Terminate the current statement.
2232 restart = TRUE;
2233 end = TRUE;
2235 break;
2240 if (! end)
2242 c = skipToNonWhite ();
2243 if (c == EOF)
2244 end = TRUE;
2246 } while (! end);
2248 if (restart)
2249 restartStatement (st);
2250 else
2251 setToken (st, TOKEN_NONE);
2252 return (boolean) (c != EOF);
2255 static void skipJavaThrows (statementInfo *const st)
2257 tokenInfo *const token = activeToken (st);
2258 int c = skipToNonWhite ();
2260 if (isident1 (c))
2262 readIdentifier (token, c);
2263 if (token->keyword == KEYWORD_THROWS)
2267 c = skipToNonWhite ();
2268 if (isident1 (c))
2270 readIdentifier (token, c);
2271 c = skipToNonWhite ();
2273 } while (c == '.' || c == ',');
2276 cppUngetc (c);
2277 setToken (st, TOKEN_NONE);
2280 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2282 const unsigned long inputLineNumber = getInputLineNumber ();
2283 int c = skipToNonWhite ();
2285 cppUngetc (c);
2286 if (isOneOf (c, "{;,="))
2288 else if (isLanguage (Lang_java) || isLanguage (Lang_vala))
2289 skipJavaThrows (st);
2290 else
2292 if (! skipPostArgumentStuff (st, info))
2294 verbose (
2295 "%s: confusing argument declarations beginning at line %lu\n",
2296 getInputFileName (), inputLineNumber);
2297 longjmp (Exception, (int) ExceptionFormattingError);
2302 static int parseParens (statementInfo *const st, parenInfo *const info)
2304 tokenInfo *const token = activeToken (st);
2305 unsigned int identifierCount = 0;
2306 unsigned int depth = 1;
2307 boolean firstChar = TRUE;
2308 int nextChar = '\0';
2310 info->parameterCount = 1;
2313 int c = skipToNonWhite ();
2315 switch (c)
2317 case '&':
2318 case '*':
2320 /* DEBUG_PRINT("parseParens, po++\n"); */
2321 info->isKnrParamList = FALSE;
2322 if (identifierCount == 0)
2323 info->isParamList = FALSE;
2324 initToken (token);
2325 break;
2327 case ':':
2329 info->isKnrParamList = FALSE;
2330 break;
2332 case '.':
2334 info->isNameCandidate = FALSE;
2335 info->isKnrParamList = FALSE;
2336 break;
2338 case ',':
2340 info->isNameCandidate = FALSE;
2341 if (info->isKnrParamList)
2343 ++info->parameterCount;
2344 identifierCount = 0;
2346 break;
2348 case '=':
2350 info->isKnrParamList = FALSE;
2351 info->isNameCandidate = FALSE;
2352 if (firstChar)
2354 info->isParamList = FALSE;
2355 skipMacro (st);
2356 depth = 0;
2358 break;
2360 case '[':
2362 info->isKnrParamList = FALSE;
2363 skipToMatch ("[]");
2364 break;
2366 case '<':
2368 info->isKnrParamList = FALSE;
2369 skipToMatch ("<>");
2370 break;
2372 case ')':
2374 if (firstChar)
2375 info->parameterCount = 0;
2376 --depth;
2377 break;
2379 case '(':
2381 info->isKnrParamList = FALSE;
2382 if (firstChar)
2384 info->isNameCandidate = FALSE;
2385 cppUngetc (c);
2386 skipMacro (st);
2387 depth = 0;
2389 else if (isType (token, TOKEN_PAREN_NAME))
2391 c = skipToNonWhite ();
2392 if (c == '*') /* check for function pointer */
2394 skipToMatch ("()");
2395 c = skipToNonWhite ();
2396 if (c == '(')
2397 skipToMatch ("()");
2399 else
2401 cppUngetc (c);
2402 cppUngetc ('(');
2403 info->nestedArgs = TRUE;
2406 else
2407 ++depth;
2408 break;
2411 default:
2413 if (isident1 (c))
2415 if (++identifierCount > 1)
2416 info->isKnrParamList = FALSE;
2417 readIdentifier (token, c);
2418 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2419 token->type = TOKEN_PAREN_NAME;
2420 else if (isType (token, TOKEN_KEYWORD))
2422 info->isKnrParamList = FALSE;
2423 info->isNameCandidate = FALSE;
2426 else
2428 info->isParamList = FALSE;
2429 info->isKnrParamList = FALSE;
2430 info->isNameCandidate = FALSE;
2431 info->invalidContents = TRUE;
2433 break;
2436 firstChar = FALSE;
2437 } while (! info->nestedArgs && depth > 0 &&
2438 (info->isKnrParamList || info->isNameCandidate));
2440 if (! info->nestedArgs) while (depth > 0)
2442 skipToMatch ("()");
2443 --depth;
2445 if (st->argEndPosition == 0)
2447 if (useFile())
2448 st->argEndPosition = ftell(File.fp);
2449 else
2450 /* FIXME File.fpBufferPosition is wrong here, this breaks function signatures and
2451 * so Geany's calltips */
2452 st->argEndPosition = File.fpBufferPosition;
2455 if (! info->isNameCandidate)
2456 initToken (token);
2458 return nextChar;
2461 static void initParenInfo (parenInfo *const info)
2463 info->isParamList = TRUE;
2464 info->isKnrParamList = TRUE;
2465 info->isNameCandidate = TRUE;
2466 info->invalidContents = FALSE;
2467 info->nestedArgs = FALSE;
2468 info->parameterCount = 0;
2471 static void analyzeParens (statementInfo *const st)
2473 tokenInfo *const prev = prevToken (st, 1);
2475 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2477 tokenInfo *const token = activeToken (st);
2478 parenInfo info;
2479 int c;
2481 initParenInfo (&info);
2482 parseParens (st, &info);
2484 c = skipToNonWhite ();
2486 cppUngetc (c);
2487 if (info.invalidContents)
2489 reinitStatement (st, FALSE);
2491 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2492 ! st->gotParenName &&
2493 (! info.isParamList || ! st->haveQualifyingName ||
2494 c == '(' ||
2495 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2496 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2498 token->type = TOKEN_NAME;
2499 processName (st);
2500 st->gotParenName = TRUE;
2502 else if (! st->gotArgs && info.isParamList)
2504 st->gotArgs = TRUE;
2505 setToken (st, TOKEN_ARGS);
2506 advanceToken (st);
2507 analyzePostParens (st, &info);
2509 else
2511 setToken (st, TOKEN_NONE);
2517 * Token parsing functions
2520 static void addContext (statementInfo *const st, const tokenInfo* const token)
2522 if (isType (token, TOKEN_NAME))
2524 if (vStringLength (st->context->name) > 0)
2526 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
2527 vStringCatS (st->context->name, "::");
2528 else if (isLanguage (Lang_java) ||
2529 isLanguage (Lang_d) || isLanguage (Lang_ferite) ||
2530 isLanguage (Lang_csharp) || isLanguage (Lang_vala))
2531 vStringCatS (st->context->name, ".");
2533 vStringCat (st->context->name, token->name);
2534 st->context->type = TOKEN_NAME;
2538 static boolean inheritingDeclaration (declType decl)
2540 return (boolean) (decl == DECL_CLASS ||
2541 decl == DECL_STRUCT ||
2542 decl == DECL_INTERFACE);
2545 static void processColon (statementInfo *const st)
2547 int c = skipToNonWhite ();
2548 const boolean doubleColon = (boolean) (c == ':');
2550 if (doubleColon)
2552 setToken (st, TOKEN_DOUBLE_COLON);
2553 st->haveQualifyingName = FALSE;
2555 else
2557 cppUngetc (c);
2558 if ((((isLanguage (Lang_cpp) &&
2559 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT)) ||
2560 isLanguage (Lang_csharp) || isLanguage (Lang_vala)) &&
2561 inheritingDeclaration (st->declaration)) ||
2562 isLanguage (Lang_d))
2564 readParents (st, ':');
2566 else if (parentDecl (st) == DECL_STRUCT || parentDecl (st) == DECL_CLASS)
2568 c = skipToOneOf (",;");
2569 if (c == ',')
2570 setToken (st, TOKEN_COMMA);
2571 else if (c == ';')
2572 setToken (st, TOKEN_SEMICOLON);
2574 else
2576 const tokenInfo *const prev = prevToken (st, 1);
2577 const tokenInfo *const prev2 = prevToken (st, 2);
2578 if (prev->keyword == KEYWORD_DEFAULT ||
2579 prev2->keyword == KEYWORD_CASE ||
2580 st->parent != NULL)
2582 reinitStatement (st, FALSE);
2588 /* Skips over any initializing value which may follow an '=' character in a
2589 * variable definition.
2591 static int skipInitializer (statementInfo *const st)
2593 boolean done = FALSE;
2594 int c;
2596 while (! done)
2598 c = skipToNonWhite ();
2600 if (c == EOF)
2601 longjmp (Exception, (int) ExceptionFormattingError);
2602 else switch (c)
2604 case ',':
2605 case ';': done = TRUE; break;
2607 case '0':
2608 if (st->implementation == IMP_VIRTUAL)
2609 st->implementation = IMP_PURE_VIRTUAL;
2610 break;
2612 case '[': skipToMatch ("[]"); break;
2613 case '(': skipToMatch ("()"); break;
2614 case '{': skipToMatch ("{}"); break;
2616 case '}':
2617 if (insideEnumBody (st))
2618 done = TRUE;
2619 else if (! isBraceFormat ())
2621 verbose ("%s: unexpected closing brace at line %lu\n",
2622 getInputFileName (), getInputLineNumber ());
2623 longjmp (Exception, (int) ExceptionBraceFormattingError);
2625 break;
2627 default: break;
2630 return c;
2633 static void processInitializer (statementInfo *const st)
2635 const boolean inEnumBody = insideEnumBody (st);
2636 const int c = skipInitializer (st);
2638 if (c == ';')
2639 setToken (st, TOKEN_SEMICOLON);
2640 else if (c == ',')
2641 setToken (st, TOKEN_COMMA);
2642 else if (c == '}' && inEnumBody)
2644 cppUngetc (c);
2645 setToken (st, TOKEN_COMMA);
2647 if (st->scope == SCOPE_EXTERN)
2648 st->scope = SCOPE_GLOBAL;
2651 static void parseIdentifier (statementInfo *const st, const int c)
2653 tokenInfo *const token = activeToken (st);
2655 readIdentifier (token, c);
2656 if (! isType (token, TOKEN_NONE))
2657 processToken (token, st);
2660 static void parseGeneralToken (statementInfo *const st, const int c)
2662 const tokenInfo *const prev = prevToken (st, 1);
2664 if (isident1(c))
2666 parseIdentifier (st, c);
2667 if (isType (st->context, TOKEN_NAME) &&
2668 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2670 initToken (st->context);
2673 else if (isExternCDecl (st, c))
2675 st->declaration = DECL_NOMANGLE;
2676 st->scope = SCOPE_GLOBAL;
2680 /* Reads characters from the pre-processor and assembles tokens, setting
2681 * the current statement state.
2683 static void nextToken (statementInfo *const st)
2685 int c;
2686 tokenInfo *token = activeToken (st);
2689 c = skipToNonWhite();
2690 switch (c)
2692 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2693 case '(': analyzeParens (st); token = activeToken (st); break;
2694 case '*': setToken (st, TOKEN_STAR); break;
2695 case ',': setToken (st, TOKEN_COMMA); break;
2696 case ':': processColon (st); break;
2697 case ';': setToken (st, TOKEN_SEMICOLON); break;
2698 case '<': skipToMatch ("<>"); break;
2699 case '=': processInitializer (st); break;
2700 case '[':
2701 /* Hack for Vala: [..] can be a function attribute.
2702 * Seems not to have bad side effects, but have to test it more. */
2703 if (!isLanguage (Lang_vala))
2704 setToken (st, TOKEN_ARRAY);
2705 skipToMatch ("[]");
2706 break;
2707 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2708 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2709 default: parseGeneralToken (st, c); break;
2711 } while (isType (token, TOKEN_NONE));
2713 /* We want to know about non-keyword variable types */
2714 if (TOKEN_NONE == st->firstToken->type)
2716 if ((TOKEN_NAME == token->type) || isDataTypeKeyword(token))
2717 copyToken(st->firstToken, token);
2722 * Scanning support functions
2724 static unsigned int contextual_fake_count = 0;
2725 static statementInfo *CurrentStatement = NULL;
2727 static statementInfo *newStatement (statementInfo *const parent)
2729 statementInfo *const st = xMalloc (1, statementInfo);
2730 unsigned int i;
2732 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2733 st->token [i] = newToken ();
2735 st->context = newToken ();
2736 st->blockName = newToken ();
2737 st->parentClasses = vStringNew ();
2738 st->firstToken = newToken();
2740 initStatement (st, parent);
2741 CurrentStatement = st;
2743 return st;
2746 static void deleteStatement (void)
2748 statementInfo *const st = CurrentStatement;
2749 statementInfo *const parent = st->parent;
2750 unsigned int i;
2752 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2754 deleteToken(st->token[i]); st->token[i] = NULL;
2756 deleteToken(st->blockName); st->blockName = NULL;
2757 deleteToken(st->context); st->context = NULL;
2758 vStringDelete(st->parentClasses); st->parentClasses = NULL;
2759 deleteToken(st->firstToken);
2760 eFree (st);
2761 CurrentStatement = parent;
2764 static void deleteAllStatements (void)
2766 while (CurrentStatement != NULL)
2767 deleteStatement ();
2770 static boolean isStatementEnd (const statementInfo *const st)
2772 const tokenInfo *const token = activeToken (st);
2773 boolean isEnd;
2775 if (isType (token, TOKEN_SEMICOLON))
2776 isEnd = TRUE;
2777 else if (isType (token, TOKEN_BRACE_CLOSE))
2778 /* Java, D, C#, Vala do not require semicolons to end a block. Neither do
2779 * C++ namespaces. All other blocks require a semicolon to terminate them.
2781 isEnd = (boolean) (isLanguage (Lang_java) || isLanguage (Lang_d) ||
2782 isLanguage (Lang_csharp) || isLanguage (Lang_vala) ||
2783 ! isContextualStatement (st));
2784 else
2785 isEnd = FALSE;
2787 return isEnd;
2790 static void checkStatementEnd (statementInfo *const st)
2792 const tokenInfo *const token = activeToken (st);
2793 boolean comma = isType (token, TOKEN_COMMA);
2795 if (comma || isStatementEnd (st))
2797 reinitStatementWithToken (st, activeToken (st), comma);
2799 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2800 cppEndStatement ();
2802 else
2804 cppBeginStatement ();
2805 advanceToken (st);
2809 static void nest (statementInfo *const st, const unsigned int nestLevel)
2811 switch (st->declaration)
2813 case DECL_CLASS:
2814 case DECL_ENUM:
2815 case DECL_INTERFACE:
2816 case DECL_NAMESPACE:
2817 case DECL_NOMANGLE:
2818 case DECL_STRUCT:
2819 case DECL_UNION:
2820 createTags (nestLevel, st);
2821 break;
2822 default:
2823 skipToMatch ("{}");
2824 break;
2826 advanceToken (st);
2827 setToken (st, TOKEN_BRACE_CLOSE);
2830 static void tagCheck (statementInfo *const st)
2832 const tokenInfo *const token = activeToken (st);
2833 const tokenInfo *const prev = prevToken (st, 1);
2834 const tokenInfo *const prev2 = prevToken (st, 2);
2836 switch (token->type)
2838 case TOKEN_NAME:
2840 if (insideEnumBody (st))
2841 qualifyEnumeratorTag (st, token);
2842 break;
2844 #if 0
2845 case TOKEN_PACKAGE:
2847 if (st->haveQualifyingName)
2848 makeTag (token, st, FALSE, TAG_PACKAGE);
2849 break;
2851 #endif
2852 case TOKEN_BRACE_OPEN:
2854 if (isType (prev, TOKEN_ARGS))
2856 if (st->haveQualifyingName)
2858 st->declaration = DECL_FUNCTION;
2859 if (isType (prev2, TOKEN_NAME))
2860 copyToken (st->blockName, prev2);
2861 qualifyFunctionTag (st, prev2);
2864 else if (isContextualStatement (st))
2866 tokenInfo *name_token = (tokenInfo *)prev;
2868 if (isType (name_token, TOKEN_NAME))
2870 if (!isLanguage (Lang_vala))
2871 copyToken (st->blockName, name_token);
2872 else
2874 switch (st->declaration)
2876 case DECL_CLASS:
2877 case DECL_ENUM:
2878 case DECL_INTERFACE:
2879 case DECL_NAMESPACE:
2880 case DECL_STRUCT:
2881 copyToken (st->blockName, name_token);
2882 break;
2884 /* anything else can be a property */
2885 default:
2886 /* makeTag (prev, st, FALSE, TAG_PROPERTY); */
2887 /* FIXME: temporary hack to get properties shown */
2888 makeTag (prev, st, FALSE, TAG_FIELD);
2889 break;
2893 else if (isLanguage (Lang_csharp))
2894 makeTag (prev, st, FALSE, TAG_PROPERTY);
2895 else
2897 tokenInfo *contextual_token = (tokenInfo *)prev;
2898 if(isContextualKeyword (contextual_token))
2900 char buffer[64];
2902 name_token = newToken ();
2903 copyToken (name_token, contextual_token);
2905 sprintf(buffer, "anon_%s_%d", name_token->name->buffer, contextual_fake_count++);
2906 vStringClear(name_token->name);
2907 vStringCatS(name_token->name, buffer);
2909 name_token->type = TOKEN_NAME;
2910 name_token->keyword = KEYWORD_NONE;
2912 advanceToken (st);
2913 contextual_token = activeToken (st);
2914 copyToken (contextual_token, token);
2915 copyToken ((tokenInfo *const)token, name_token);
2916 copyToken (st->blockName, name_token);
2917 copyToken (st->firstToken, name_token);
2920 qualifyBlockTag (st, name_token);
2922 break;
2924 case TOKEN_ARRAY:
2925 case TOKEN_SEMICOLON:
2926 case TOKEN_COMMA:
2928 if (insideEnumBody (st))
2930 else if (isType (prev, TOKEN_NAME))
2932 if (isContextualKeyword (prev2))
2933 makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
2934 else
2935 qualifyVariableTag (st, prev);
2937 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
2939 qualifyFunctionDeclTag (st, prev2);
2941 break;
2943 default:
2944 break;
2948 /* Parses the current file and decides whether to write out and tags that
2949 * are discovered.
2951 static void createTags (const unsigned int nestLevel,
2952 statementInfo *const parent)
2954 statementInfo *const st = newStatement (parent);
2956 DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
2957 while (TRUE)
2959 tokenInfo *token;
2961 nextToken (st);
2963 token = activeToken (st);
2965 if (isType (token, TOKEN_BRACE_CLOSE))
2967 if (nestLevel > 0)
2968 break;
2969 else
2971 verbose ("%s: unexpected closing brace at line %lu\n",
2972 getInputFileName (), getInputLineNumber ());
2973 longjmp (Exception, (int) ExceptionBraceFormattingError);
2976 else if (isType (token, TOKEN_DOUBLE_COLON))
2978 addContext (st, prevToken (st, 1));
2979 advanceToken (st);
2981 else
2983 tagCheck (st);/* this can add new token */
2984 if (isType (activeToken (st), TOKEN_BRACE_OPEN))
2985 nest (st, nestLevel + 1);
2986 checkStatementEnd (st);
2989 deleteStatement ();
2990 DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
2993 static boolean findCTags (const unsigned int passCount)
2995 exception_t exception;
2996 boolean retry;
2998 Assert (passCount < 3);
2999 cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
3001 exception = (exception_t) setjmp (Exception);
3002 retry = FALSE;
3004 if (exception == ExceptionNone)
3006 createTags (0, NULL);
3008 else
3010 deleteAllStatements ();
3011 if (exception == ExceptionBraceFormattingError && passCount == 1)
3013 retry = TRUE;
3014 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3015 getInputFileName ());
3018 cppTerminate ();
3019 return retry;
3022 static void buildKeywordHash (const langType language, unsigned int idx)
3024 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
3025 size_t i;
3026 for (i = 0 ; i < count ; ++i)
3028 const keywordDesc* const p = &KeywordTable [i];
3029 if (p->isValid [idx])
3030 addKeyword (p->name, language, (int) p->id);
3034 static void initializeCParser (const langType language)
3036 contextual_fake_count = 0;
3037 Lang_c = language;
3038 buildKeywordHash (language, 0);
3041 static void initializeCppParser (const langType language)
3043 contextual_fake_count = 0;
3044 Lang_cpp = language;
3045 buildKeywordHash (language, 1);
3048 static void initializeJavaParser (const langType language)
3050 contextual_fake_count = 0;
3051 Lang_java = language;
3052 buildKeywordHash (language, 3);
3055 static void initializeDParser (const langType language)
3057 contextual_fake_count = 0;
3058 Lang_d = language;
3059 buildKeywordHash (language, 6);
3062 static void initializeGLSLParser (const langType language)
3064 contextual_fake_count = 0;
3065 Lang_glsl = language;
3066 buildKeywordHash (language, 0); /* C keywords */
3069 static void initializeFeriteParser (const langType language)
3071 contextual_fake_count = 0;
3072 Lang_ferite = language;
3073 buildKeywordHash (language, 1); /* C++ keywords */
3076 static void initializeCsharpParser (const langType language)
3078 contextual_fake_count = 0;
3079 Lang_csharp = language;
3080 buildKeywordHash (language, 2);
3083 static void initializeValaParser (const langType language)
3085 contextual_fake_count = 0;
3086 Lang_vala = language;
3087 buildKeywordHash (language, 5);
3090 extern parserDefinition* CParser (void)
3092 static const char *const extensions [] = { "c", "pc", "sc", NULL };
3093 parserDefinition* def = parserNew ("C");
3094 def->kinds = CKinds;
3095 def->kindCount = KIND_COUNT (CKinds);
3096 def->extensions = extensions;
3097 def->parser2 = findCTags;
3098 def->initialize = initializeCParser;
3099 return def;
3102 extern parserDefinition* CppParser (void)
3104 static const char *const extensions [] = {
3105 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3106 "i",
3107 #ifndef CASE_INSENSITIVE_FILENAMES
3108 "C", "H",
3109 #endif
3110 NULL
3112 parserDefinition* def = parserNew ("C++");
3113 def->kinds = CKinds;
3114 def->kindCount = KIND_COUNT (CKinds);
3115 def->extensions = extensions;
3116 def->parser2 = findCTags;
3117 def->initialize = initializeCppParser;
3118 return def;
3121 extern parserDefinition* JavaParser (void)
3123 static const char *const extensions [] = { "java", NULL };
3124 parserDefinition* def = parserNew ("Java");
3125 def->kinds = JavaKinds;
3126 def->kindCount = KIND_COUNT (JavaKinds);
3127 def->extensions = extensions;
3128 def->parser2 = findCTags;
3129 def->initialize = initializeJavaParser;
3130 return def;
3133 extern parserDefinition* DParser (void)
3135 static const char *const extensions [] = { "d", "di", NULL };
3136 parserDefinition* def = parserNew ("D");
3137 def->kinds = DKinds;
3138 def->kindCount = KIND_COUNT (DKinds);
3139 def->extensions = extensions;
3140 def->parser2 = findCTags;
3141 def->initialize = initializeDParser;
3142 return def;
3145 extern parserDefinition* GLSLParser (void)
3147 static const char *const extensions [] = { "glsl", "frag", "vert", NULL };
3148 parserDefinition* def = parserNew ("GLSL");
3149 def->kinds = CKinds;
3150 def->kindCount = KIND_COUNT (CKinds);
3151 def->extensions = extensions;
3152 def->parser2 = findCTags;
3153 def->initialize = initializeGLSLParser;
3154 return def;
3157 extern parserDefinition* FeriteParser (void)
3159 static const char *const extensions [] = { "fe", NULL };
3160 parserDefinition* def = parserNew ("Ferite");
3161 def->kinds = CKinds;
3162 def->kindCount = KIND_COUNT (CKinds);
3163 def->extensions = extensions;
3164 def->parser2 = findCTags;
3165 def->initialize = initializeFeriteParser;
3166 return def;
3169 extern parserDefinition* CsharpParser (void)
3171 static const char *const extensions [] = { "cs", NULL };
3172 parserDefinition* def = parserNew ("C#");
3173 def->kinds = CsharpKinds;
3174 def->kindCount = KIND_COUNT (CsharpKinds);
3175 def->extensions = extensions;
3176 def->parser2 = findCTags;
3177 def->initialize = initializeCsharpParser;
3178 return def;
3181 extern parserDefinition* ValaParser (void)
3183 static const char *const extensions [] = { "vala", NULL };
3184 parserDefinition* def = parserNew ("Vala");
3185 def->kinds = ValaKinds;
3186 def->kindCount = KIND_COUNT (ValaKinds);
3187 def->extensions = extensions;
3188 def->parser2 = findCTags;
3189 def->initialize = initializeValaParser;
3190 return def;
3192 /* vi:set tabstop=8 shiftwidth=4: */