ctags.rb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +23 -0
  3. data/ctags.rb.gemspec +23 -0
  4. data/ext/.gitignore +3 -0
  5. data/ext/extconf.rb +15 -0
  6. data/ext/vendor/exuberant-ctags/.gitignore +6 -0
  7. data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
  8. data/ext/vendor/exuberant-ctags/COPYING +340 -0
  9. data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
  10. data/ext/vendor/exuberant-ctags/FAQ +371 -0
  11. data/ext/vendor/exuberant-ctags/INSTALL +215 -0
  12. data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
  13. data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
  14. data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
  15. data/ext/vendor/exuberant-ctags/NEWS +871 -0
  16. data/ext/vendor/exuberant-ctags/README +73 -0
  17. data/ext/vendor/exuberant-ctags/ant.c +42 -0
  18. data/ext/vendor/exuberant-ctags/argproc.c +505 -0
  19. data/ext/vendor/exuberant-ctags/args.c +274 -0
  20. data/ext/vendor/exuberant-ctags/args.h +63 -0
  21. data/ext/vendor/exuberant-ctags/asm.c +387 -0
  22. data/ext/vendor/exuberant-ctags/asp.c +328 -0
  23. data/ext/vendor/exuberant-ctags/awk.c +81 -0
  24. data/ext/vendor/exuberant-ctags/basic.c +203 -0
  25. data/ext/vendor/exuberant-ctags/beta.c +321 -0
  26. data/ext/vendor/exuberant-ctags/c.c +2932 -0
  27. data/ext/vendor/exuberant-ctags/cobol.c +50 -0
  28. data/ext/vendor/exuberant-ctags/config.h.in +277 -0
  29. data/ext/vendor/exuberant-ctags/configure +7704 -0
  30. data/ext/vendor/exuberant-ctags/configure.ac +532 -0
  31. data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
  32. data/ext/vendor/exuberant-ctags/ctags.h +28 -0
  33. data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
  34. data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
  35. data/ext/vendor/exuberant-ctags/debug.c +113 -0
  36. data/ext/vendor/exuberant-ctags/debug.h +70 -0
  37. data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
  38. data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
  39. data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
  40. data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
  41. data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
  42. data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
  43. data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
  44. data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
  45. data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
  46. data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
  47. data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
  48. data/ext/vendor/exuberant-ctags/entry.c +847 -0
  49. data/ext/vendor/exuberant-ctags/entry.h +103 -0
  50. data/ext/vendor/exuberant-ctags/erlang.c +189 -0
  51. data/ext/vendor/exuberant-ctags/flex.c +2243 -0
  52. data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
  53. data/ext/vendor/exuberant-ctags/general.h +127 -0
  54. data/ext/vendor/exuberant-ctags/get.c +669 -0
  55. data/ext/vendor/exuberant-ctags/get.h +50 -0
  56. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
  57. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
  58. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
  59. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
  60. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
  61. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
  62. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
  63. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
  64. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
  65. data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
  66. data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
  67. data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
  68. data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
  69. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
  70. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
  71. data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
  72. data/ext/vendor/exuberant-ctags/html.c +49 -0
  73. data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
  74. data/ext/vendor/exuberant-ctags/keyword.c +258 -0
  75. data/ext/vendor/exuberant-ctags/keyword.h +34 -0
  76. data/ext/vendor/exuberant-ctags/lisp.c +139 -0
  77. data/ext/vendor/exuberant-ctags/lregex.c +704 -0
  78. data/ext/vendor/exuberant-ctags/lua.c +133 -0
  79. data/ext/vendor/exuberant-ctags/mac.c +273 -0
  80. data/ext/vendor/exuberant-ctags/magic.diff +21 -0
  81. data/ext/vendor/exuberant-ctags/main.c +584 -0
  82. data/ext/vendor/exuberant-ctags/main.h +32 -0
  83. data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
  84. data/ext/vendor/exuberant-ctags/make.c +217 -0
  85. data/ext/vendor/exuberant-ctags/matlab.c +44 -0
  86. data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
  87. data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
  88. data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
  89. data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
  90. data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
  91. data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
  92. data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
  93. data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
  94. data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
  95. data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
  96. data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
  97. data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
  98. data/ext/vendor/exuberant-ctags/options.c +1842 -0
  99. data/ext/vendor/exuberant-ctags/options.h +155 -0
  100. data/ext/vendor/exuberant-ctags/parse.c +677 -0
  101. data/ext/vendor/exuberant-ctags/parse.h +129 -0
  102. data/ext/vendor/exuberant-ctags/parsers.h +63 -0
  103. data/ext/vendor/exuberant-ctags/pascal.c +267 -0
  104. data/ext/vendor/exuberant-ctags/perl.c +382 -0
  105. data/ext/vendor/exuberant-ctags/php.c +237 -0
  106. data/ext/vendor/exuberant-ctags/python.c +771 -0
  107. data/ext/vendor/exuberant-ctags/qdos.c +106 -0
  108. data/ext/vendor/exuberant-ctags/read.c +569 -0
  109. data/ext/vendor/exuberant-ctags/read.h +116 -0
  110. data/ext/vendor/exuberant-ctags/readtags.c +959 -0
  111. data/ext/vendor/exuberant-ctags/readtags.h +252 -0
  112. data/ext/vendor/exuberant-ctags/rexx.c +39 -0
  113. data/ext/vendor/exuberant-ctags/routines.c +891 -0
  114. data/ext/vendor/exuberant-ctags/routines.h +134 -0
  115. data/ext/vendor/exuberant-ctags/ruby.c +408 -0
  116. data/ext/vendor/exuberant-ctags/scheme.c +111 -0
  117. data/ext/vendor/exuberant-ctags/sh.c +115 -0
  118. data/ext/vendor/exuberant-ctags/slang.c +41 -0
  119. data/ext/vendor/exuberant-ctags/sml.c +212 -0
  120. data/ext/vendor/exuberant-ctags/sort.c +230 -0
  121. data/ext/vendor/exuberant-ctags/sort.h +32 -0
  122. data/ext/vendor/exuberant-ctags/source.mak +122 -0
  123. data/ext/vendor/exuberant-ctags/sql.c +2112 -0
  124. data/ext/vendor/exuberant-ctags/strlist.c +281 -0
  125. data/ext/vendor/exuberant-ctags/strlist.h +54 -0
  126. data/ext/vendor/exuberant-ctags/tcl.c +116 -0
  127. data/ext/vendor/exuberant-ctags/tex.c +524 -0
  128. data/ext/vendor/exuberant-ctags/verilog.c +340 -0
  129. data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
  130. data/ext/vendor/exuberant-ctags/vim.c +636 -0
  131. data/ext/vendor/exuberant-ctags/vstring.c +232 -0
  132. data/ext/vendor/exuberant-ctags/vstring.h +85 -0
  133. data/ext/vendor/exuberant-ctags/yacc.c +40 -0
  134. data/lib/ctags/exuberant.rb +45 -0
  135. data/lib/ctags/version.rb +3 -0
  136. data/lib/ctags.rb +6 -0
  137. data/test/test_ctags.rb +24 -0
  138. metadata +233 -0
@@ -0,0 +1,2932 @@
1
+ /*
2
+ * $Id: c.c 689 2008-12-13 21:17:36Z elliotth $
3
+ *
4
+ * Copyright (c) 1996-2003, Darren Hiebert
5
+ *
6
+ * This source code is released for free distribution under the terms of the
7
+ * GNU General Public License.
8
+ *
9
+ * This module contains functions for parsing and scanning C, C++ and Java
10
+ * source files.
11
+ */
12
+
13
+ /*
14
+ * INCLUDE FILES
15
+ */
16
+ #include "general.h" /* must always come first */
17
+
18
+ #include <string.h>
19
+ #include <setjmp.h>
20
+
21
+ #include "debug.h"
22
+ #include "entry.h"
23
+ #include "get.h"
24
+ #include "keyword.h"
25
+ #include "options.h"
26
+ #include "parse.h"
27
+ #include "read.h"
28
+ #include "routines.h"
29
+
30
+ /*
31
+ * MACROS
32
+ */
33
+
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) ((st)->parent == NULL ? FALSE : \
39
+ (boolean) ((st)->parent->declaration == DECL_ENUM))
40
+ #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
41
+ ! (st)->haveQualifyingName && (st)->scope == SCOPE_EXTERN)
42
+
43
+ #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
44
+
45
+ #define isHighChar(c) ((c) != EOF && (unsigned char)(c) >= 0xc0)
46
+
47
+ /*
48
+ * DATA DECLARATIONS
49
+ */
50
+
51
+ enum { NumTokens = 3 };
52
+
53
+ typedef enum eException {
54
+ ExceptionNone, ExceptionEOF, ExceptionFormattingError,
55
+ ExceptionBraceFormattingError
56
+ } exception_t;
57
+
58
+ /* Used to specify type of keyword.
59
+ */
60
+ typedef enum eKeywordId {
61
+ KEYWORD_NONE = -1,
62
+ KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT,
63
+ KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
64
+ KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT,
65
+ KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
66
+ KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
67
+ KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
68
+ KEYWORD_DOUBLE,
69
+ KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
70
+ KEYWORD_EXTENDS, KEYWORD_EVENT,
71
+ KEYWORD_FINAL, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FOREACH,
72
+ KEYWORD_FRIEND, KEYWORD_FUNCTION,
73
+ KEYWORD_GOTO,
74
+ KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, 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_MUTABLE,
80
+ KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE,
81
+ KEYWORD_OPERATOR, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
82
+ KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE,
83
+ KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
84
+ KEYWORD_REGISTER, KEYWORD_RETURN,
85
+ KEYWORD_SHADOW, KEYWORD_STATE,
86
+ KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STRING,
87
+ KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
88
+ KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
89
+ KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
90
+ KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
91
+ KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
92
+ KEYWORD_USING,
93
+ KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
94
+ KEYWORD_WCHAR_T, KEYWORD_WHILE
95
+ } keywordId;
96
+
97
+ /* Used to determine whether keyword is valid for the current language and
98
+ * what its ID is.
99
+ */
100
+ typedef struct sKeywordDesc {
101
+ const char *name;
102
+ keywordId id;
103
+ short isValid [5]; /* indicates languages for which kw is valid */
104
+ } keywordDesc;
105
+
106
+ /* Used for reporting the type of object parsed by nextToken ().
107
+ */
108
+ 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_COLON, /* the colon character */
114
+ TOKEN_COMMA, /* the comma character */
115
+ TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
116
+ TOKEN_KEYWORD,
117
+ TOKEN_NAME, /* an unknown name */
118
+ TOKEN_PACKAGE, /* a Java package name */
119
+ TOKEN_PAREN_NAME, /* a single name in parentheses */
120
+ TOKEN_SEMICOLON, /* the semicolon character */
121
+ TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
122
+ TOKEN_COUNT
123
+ } tokenType;
124
+
125
+ /* This describes the scoping of the current statement.
126
+ */
127
+ typedef enum eTagScope {
128
+ SCOPE_GLOBAL, /* no storage class specified */
129
+ SCOPE_STATIC, /* static storage class */
130
+ SCOPE_EXTERN, /* external storage class */
131
+ SCOPE_FRIEND, /* declares access only */
132
+ SCOPE_TYPEDEF, /* scoping depends upon context */
133
+ SCOPE_COUNT
134
+ } tagScope;
135
+
136
+ typedef enum eDeclaration {
137
+ DECL_NONE,
138
+ DECL_BASE, /* base type (default) */
139
+ DECL_CLASS,
140
+ DECL_ENUM,
141
+ DECL_EVENT,
142
+ DECL_FUNCTION,
143
+ DECL_IGNORE, /* non-taggable "declaration" */
144
+ DECL_INTERFACE,
145
+ DECL_NAMESPACE,
146
+ DECL_NOMANGLE, /* C++ name demangling block */
147
+ DECL_PACKAGE,
148
+ DECL_PROGRAM, /* Vera program */
149
+ DECL_STRUCT,
150
+ DECL_TASK, /* Vera task */
151
+ DECL_UNION,
152
+ DECL_COUNT
153
+ } declType;
154
+
155
+ typedef enum eVisibilityType {
156
+ ACCESS_UNDEFINED,
157
+ ACCESS_LOCAL,
158
+ ACCESS_PRIVATE,
159
+ ACCESS_PROTECTED,
160
+ ACCESS_PUBLIC,
161
+ ACCESS_DEFAULT, /* Java-specific */
162
+ ACCESS_COUNT
163
+ } accessType;
164
+
165
+ /* Information about the parent class of a member (if any).
166
+ */
167
+ typedef struct sMemberInfo {
168
+ accessType access; /* access of current statement */
169
+ accessType accessDefault; /* access default for current statement */
170
+ } memberInfo;
171
+
172
+ typedef struct sTokenInfo {
173
+ tokenType type;
174
+ keywordId keyword;
175
+ vString* name; /* the name of the token */
176
+ unsigned long lineNumber; /* line number of tag */
177
+ fpos_t filePosition; /* file position of line containing name */
178
+ } tokenInfo;
179
+
180
+ typedef enum eImplementation {
181
+ IMP_DEFAULT,
182
+ IMP_ABSTRACT,
183
+ IMP_VIRTUAL,
184
+ IMP_PURE_VIRTUAL,
185
+ IMP_COUNT
186
+ } impType;
187
+
188
+ /* Describes the statement currently undergoing analysis.
189
+ */
190
+ typedef struct sStatementInfo {
191
+ tagScope scope;
192
+ declType declaration; /* specifier associated with TOKEN_SPEC */
193
+ boolean gotName; /* was a name parsed yet? */
194
+ boolean haveQualifyingName; /* do we have a name we are considering? */
195
+ boolean gotParenName; /* was a name inside parentheses parsed yet? */
196
+ boolean gotArgs; /* was a list of parameters parsed yet? */
197
+ boolean isPointer; /* is 'name' a pointer? */
198
+ boolean inFunction; /* are we inside of a function? */
199
+ boolean assignment; /* have we handled an '='? */
200
+ boolean notVariable; /* has a variable declaration been disqualified ? */
201
+ impType implementation; /* abstract or concrete implementation? */
202
+ unsigned int tokenIndex; /* currently active token */
203
+ tokenInfo* token [(int) NumTokens];
204
+ tokenInfo* context; /* accumulated scope of current statement */
205
+ tokenInfo* blockName; /* name of current block */
206
+ memberInfo member; /* information regarding parent class/struct */
207
+ vString* parentClasses; /* parent classes */
208
+ struct sStatementInfo *parent; /* statement we are nested within */
209
+ } statementInfo;
210
+
211
+ /* Describes the type of tag being generated.
212
+ */
213
+ typedef enum eTagType {
214
+ TAG_UNDEFINED,
215
+ TAG_CLASS, /* class name */
216
+ TAG_ENUM, /* enumeration name */
217
+ TAG_ENUMERATOR, /* enumerator (enumeration value) */
218
+ TAG_EVENT, /* event */
219
+ TAG_FIELD, /* field (Java) */
220
+ TAG_FUNCTION, /* function definition */
221
+ TAG_INTERFACE, /* interface declaration */
222
+ TAG_LOCAL, /* local variable definition */
223
+ TAG_MEMBER, /* structure, class or interface member */
224
+ TAG_METHOD, /* method declaration */
225
+ TAG_NAMESPACE, /* namespace name */
226
+ TAG_PACKAGE, /* package name */
227
+ TAG_PROGRAM, /* program name */
228
+ TAG_PROPERTY, /* property name */
229
+ TAG_PROTOTYPE, /* function prototype or declaration */
230
+ TAG_STRUCT, /* structure name */
231
+ TAG_TASK, /* task name */
232
+ TAG_TYPEDEF, /* typedef name */
233
+ TAG_UNION, /* union name */
234
+ TAG_VARIABLE, /* variable definition */
235
+ TAG_EXTERN_VAR, /* external variable declaration */
236
+ TAG_COUNT /* must be last */
237
+ } tagType;
238
+
239
+ typedef struct sParenInfo {
240
+ boolean isPointer;
241
+ boolean isParamList;
242
+ boolean isKnrParamList;
243
+ boolean isNameCandidate;
244
+ boolean invalidContents;
245
+ boolean nestedArgs;
246
+ unsigned int parameterCount;
247
+ } parenInfo;
248
+
249
+ /*
250
+ * DATA DEFINITIONS
251
+ */
252
+
253
+ static jmp_buf Exception;
254
+
255
+ static langType Lang_c;
256
+ static langType Lang_cpp;
257
+ static langType Lang_csharp;
258
+ static langType Lang_java;
259
+ static langType Lang_vera;
260
+ static vString *Signature;
261
+ static boolean CollectingSignature;
262
+
263
+ /* Number used to uniquely identify anonymous structs and unions. */
264
+ static int AnonymousID = 0;
265
+
266
+ /* Used to index into the CKinds table. */
267
+ typedef enum {
268
+ CK_UNDEFINED = -1,
269
+ CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
270
+ CK_ENUMERATION, CK_LOCAL, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
271
+ CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
272
+ CK_EXTERN_VARIABLE
273
+ } cKind;
274
+
275
+ static kindOption CKinds [] = {
276
+ { TRUE, 'c', "class", "classes"},
277
+ { TRUE, 'd', "macro", "macro definitions"},
278
+ { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
279
+ { TRUE, 'f', "function", "function definitions"},
280
+ { TRUE, 'g', "enum", "enumeration names"},
281
+ { FALSE, 'l', "local", "local variables"},
282
+ { TRUE, 'm', "member", "class, struct, and union members"},
283
+ { TRUE, 'n', "namespace", "namespaces"},
284
+ { FALSE, 'p', "prototype", "function prototypes"},
285
+ { TRUE, 's', "struct", "structure names"},
286
+ { TRUE, 't', "typedef", "typedefs"},
287
+ { TRUE, 'u', "union", "union names"},
288
+ { TRUE, 'v', "variable", "variable definitions"},
289
+ { FALSE, 'x', "externvar", "external and forward variable declarations"},
290
+ };
291
+
292
+ typedef enum {
293
+ CSK_UNDEFINED = -1,
294
+ CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
295
+ CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
296
+ CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
297
+ } csharpKind;
298
+
299
+ static kindOption CsharpKinds [] = {
300
+ { TRUE, 'c', "class", "classes"},
301
+ { TRUE, 'd', "macro", "macro definitions"},
302
+ { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
303
+ { TRUE, 'E', "event", "events"},
304
+ { TRUE, 'f', "field", "fields"},
305
+ { TRUE, 'g', "enum", "enumeration names"},
306
+ { TRUE, 'i', "interface", "interfaces"},
307
+ { FALSE, 'l', "local", "local variables"},
308
+ { TRUE, 'm', "method", "methods"},
309
+ { TRUE, 'n', "namespace", "namespaces"},
310
+ { TRUE, 'p', "property", "properties"},
311
+ { TRUE, 's', "struct", "structure names"},
312
+ { TRUE, 't', "typedef", "typedefs"},
313
+ };
314
+
315
+ /* Used to index into the JavaKinds table. */
316
+ typedef enum {
317
+ JK_UNDEFINED = -1,
318
+ JK_CLASS, JK_ENUM_CONSTANT, JK_FIELD, JK_ENUM, JK_INTERFACE,
319
+ JK_LOCAL, JK_METHOD, JK_PACKAGE, JK_ACCESS, JK_CLASS_PREFIX
320
+ } javaKind;
321
+
322
+ static kindOption JavaKinds [] = {
323
+ { TRUE, 'c', "class", "classes"},
324
+ { TRUE, 'e', "enum constant", "enum constants"},
325
+ { TRUE, 'f', "field", "fields"},
326
+ { TRUE, 'g', "enum", "enum types"},
327
+ { TRUE, 'i', "interface", "interfaces"},
328
+ { FALSE, 'l', "local", "local variables"},
329
+ { TRUE, 'm', "method", "methods"},
330
+ { TRUE, 'p', "package", "packages"},
331
+ };
332
+
333
+ /* Used to index into the VeraKinds table. */
334
+ typedef enum {
335
+ VK_UNDEFINED = -1,
336
+ VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FUNCTION,
337
+ VK_ENUMERATION, VK_LOCAL, VK_MEMBER, VK_PROGRAM, VK_PROTOTYPE,
338
+ VK_TASK, VK_TYPEDEF, VK_VARIABLE,
339
+ VK_EXTERN_VARIABLE
340
+ } veraKind;
341
+
342
+ static kindOption VeraKinds [] = {
343
+ { TRUE, 'c', "class", "classes"},
344
+ { TRUE, 'd', "macro", "macro definitions"},
345
+ { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
346
+ { TRUE, 'f', "function", "function definitions"},
347
+ { TRUE, 'g', "enum", "enumeration names"},
348
+ { FALSE, 'l', "local", "local variables"},
349
+ { TRUE, 'm', "member", "class, struct, and union members"},
350
+ { TRUE, 'p', "program", "programs"},
351
+ { FALSE, 'P', "prototype", "function prototypes"},
352
+ { TRUE, 't', "task", "tasks"},
353
+ { TRUE, 'T', "typedef", "typedefs"},
354
+ { TRUE, 'v', "variable", "variable definitions"},
355
+ { FALSE, 'x', "externvar", "external variable declarations"}
356
+ };
357
+
358
+ static const keywordDesc KeywordTable [] = {
359
+ /* C++ */
360
+ /* ANSI C | C# Java */
361
+ /* | | | | Vera */
362
+ /* keyword keyword ID | | | | | */
363
+ { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0 } },
364
+ { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0 } },
365
+ { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1 } },
366
+ { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1 } },
367
+ { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1 } },
368
+ { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1 } },
369
+ { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1 } },
370
+ { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0 } },
371
+ { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0 } },
372
+ { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0 } },
373
+ { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0 } },
374
+ { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0 } },
375
+ { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1 } },
376
+ { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0 } },
377
+ { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1 } },
378
+ { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1 } },
379
+ { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1 } },
380
+ { "do", KEYWORD_DO, { 1, 1, 1, 1, 0 } },
381
+ { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0 } },
382
+ { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0 } },
383
+ { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0 } },
384
+ { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0 } },
385
+ { "else", KEYWORD_ELSE, { 1, 1, 1, 1, 0 } },
386
+ { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1 } },
387
+ { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1 } },
388
+ { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0 } },
389
+ { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1 } },
390
+ { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1 } },
391
+ { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0 } },
392
+ { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0 } },
393
+ { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0 } },
394
+ { "foreach", KEYWORD_FOREACH, { 0, 0, 1, 0, 0 } },
395
+ { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0 } },
396
+ { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1 } },
397
+ { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0 } },
398
+ { "if", KEYWORD_IF, { 1, 1, 1, 1, 0 } },
399
+ { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0 } },
400
+ { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0 } },
401
+ { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0 } },
402
+ { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1 } },
403
+ { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1 } },
404
+ { "int", KEYWORD_INT, { 1, 1, 1, 1, 0 } },
405
+ { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1 } },
406
+ { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1 } },
407
+ { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0 } },
408
+ { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1 } },
409
+ { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0 } },
410
+ { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1 } },
411
+ { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1 } },
412
+ { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1 } },
413
+ { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1 } },
414
+ { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0 } },
415
+ { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0 } },
416
+ { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0 } },
417
+ { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0 } },
418
+ { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1 } },
419
+ { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0 } },
420
+ { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1 } },
421
+ { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0 } },
422
+ { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0 } },
423
+ { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0 } },
424
+ { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1 } },
425
+ { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1 } },
426
+ { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0 } },
427
+ { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1 } },
428
+ { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1 } },
429
+ { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1 } },
430
+ { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0 } },
431
+ { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0 } },
432
+ { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1 } },
433
+ { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0 } },
434
+ { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0 } },
435
+ { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1 } },
436
+ { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1 } },
437
+ { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1 } },
438
+ { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0 } },
439
+ { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0 } },
440
+ { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0 } },
441
+ { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1 } },
442
+ { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0 } },
443
+ { "this", KEYWORD_THIS, { 0, 1, 1, 1, 0 } },
444
+ { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0 } },
445
+ { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0 } },
446
+ { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1 } },
447
+ { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1 } },
448
+ { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0 } },
449
+ { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0 } },
450
+ { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1 } },
451
+ { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0 } },
452
+ { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0 } },
453
+ { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0 } },
454
+ { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0 } },
455
+ { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0 } },
456
+ { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0 } },
457
+ { "using", KEYWORD_USING, { 0, 1, 1, 0, 0 } },
458
+ { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1 } },
459
+ { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1 } },
460
+ { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0 } },
461
+ { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0 } },
462
+ { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0 } }
463
+ };
464
+
465
+ /*
466
+ * FUNCTION PROTOTYPES
467
+ */
468
+ static void createTags (const unsigned int nestLevel, statementInfo *const parent);
469
+
470
+ /*
471
+ * FUNCTION DEFINITIONS
472
+ */
473
+
474
+ extern boolean includingDefineTags (void)
475
+ {
476
+ return CKinds [CK_DEFINE].enabled;
477
+ }
478
+
479
+ /*
480
+ * Token management
481
+ */
482
+
483
+ static void initToken (tokenInfo* const token)
484
+ {
485
+ token->type = TOKEN_NONE;
486
+ token->keyword = KEYWORD_NONE;
487
+ token->lineNumber = getSourceLineNumber ();
488
+ token->filePosition = getInputFilePosition ();
489
+ vStringClear (token->name);
490
+ }
491
+
492
+ static void advanceToken (statementInfo* const st)
493
+ {
494
+ if (st->tokenIndex >= (unsigned int) NumTokens - 1)
495
+ st->tokenIndex = 0;
496
+ else
497
+ ++st->tokenIndex;
498
+ initToken (st->token [st->tokenIndex]);
499
+ }
500
+
501
+ static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
502
+ {
503
+ unsigned int tokenIndex;
504
+ unsigned int num = (unsigned int) NumTokens;
505
+ Assert (n < num);
506
+ tokenIndex = (st->tokenIndex + num - n) % num;
507
+ return st->token [tokenIndex];
508
+ }
509
+
510
+ static void setToken (statementInfo *const st, const tokenType type)
511
+ {
512
+ tokenInfo *token;
513
+ token = activeToken (st);
514
+ initToken (token);
515
+ token->type = type;
516
+ }
517
+
518
+ static void retardToken (statementInfo *const st)
519
+ {
520
+ if (st->tokenIndex == 0)
521
+ st->tokenIndex = (unsigned int) NumTokens - 1;
522
+ else
523
+ --st->tokenIndex;
524
+ setToken (st, TOKEN_NONE);
525
+ }
526
+
527
+ static tokenInfo *newToken (void)
528
+ {
529
+ tokenInfo *const token = xMalloc (1, tokenInfo);
530
+ token->name = vStringNew ();
531
+ initToken (token);
532
+ return token;
533
+ }
534
+
535
+ static void deleteToken (tokenInfo *const token)
536
+ {
537
+ if (token != NULL)
538
+ {
539
+ vStringDelete (token->name);
540
+ eFree (token);
541
+ }
542
+ }
543
+
544
+ static const char *accessString (const accessType access)
545
+ {
546
+ static const char *const names [] = {
547
+ "?", "local", "private", "protected", "public", "default"
548
+ };
549
+ Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
550
+ Assert ((int) access < ACCESS_COUNT);
551
+ return names [(int) access];
552
+ }
553
+
554
+ static const char *implementationString (const impType imp)
555
+ {
556
+ static const char *const names [] ={
557
+ "?", "abstract", "virtual", "pure virtual"
558
+ };
559
+ Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
560
+ Assert ((int) imp < IMP_COUNT);
561
+ return names [(int) imp];
562
+ }
563
+
564
+ /*
565
+ * Debugging functions
566
+ */
567
+
568
+ #ifdef DEBUG
569
+
570
+ #define boolString(c) ((c) ? "TRUE" : "FALSE")
571
+
572
+ static const char *tokenString (const tokenType type)
573
+ {
574
+ static const char *const names [] = {
575
+ "none", "args", "}", "{", "colon", "comma", "double colon", "keyword",
576
+ "name", "package", "paren-name", "semicolon", "specifier"
577
+ };
578
+ Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
579
+ Assert ((int) type < TOKEN_COUNT);
580
+ return names [(int) type];
581
+ }
582
+
583
+ static const char *scopeString (const tagScope scope)
584
+ {
585
+ static const char *const names [] = {
586
+ "global", "static", "extern", "friend", "typedef"
587
+ };
588
+ Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
589
+ Assert ((int) scope < SCOPE_COUNT);
590
+ return names [(int) scope];
591
+ }
592
+
593
+ static const char *declString (const declType declaration)
594
+ {
595
+ static const char *const names [] = {
596
+ "?", "base", "class", "enum", "event", "function", "ignore",
597
+ "interface", "namespace", "no mangle", "package", "program",
598
+ "struct", "task", "union",
599
+ };
600
+ Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
601
+ Assert ((int) declaration < DECL_COUNT);
602
+ return names [(int) declaration];
603
+ }
604
+
605
+ static const char *keywordString (const keywordId keyword)
606
+ {
607
+ const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
608
+ const char *name = "none";
609
+ size_t i;
610
+ for (i = 0 ; i < count ; ++i)
611
+ {
612
+ const keywordDesc *p = &KeywordTable [i];
613
+ if (p->id == keyword)
614
+ {
615
+ name = p->name;
616
+ break;
617
+ }
618
+ }
619
+ return name;
620
+ }
621
+
622
+ static void __unused__ pt (tokenInfo *const token)
623
+ {
624
+ if (isType (token, TOKEN_NAME))
625
+ printf ("type: %-12s: %-13s line: %lu\n",
626
+ tokenString (token->type), vStringValue (token->name),
627
+ token->lineNumber);
628
+ else if (isType (token, TOKEN_KEYWORD))
629
+ printf ("type: %-12s: %-13s line: %lu\n",
630
+ tokenString (token->type), keywordString (token->keyword),
631
+ token->lineNumber);
632
+ else
633
+ printf ("type: %-12s line: %lu\n",
634
+ tokenString (token->type), token->lineNumber);
635
+ }
636
+
637
+ static void __unused__ ps (statementInfo *const st)
638
+ {
639
+ unsigned int i;
640
+ printf ("scope: %s decl: %s gotName: %s gotParenName: %s\n",
641
+ scopeString (st->scope), declString (st->declaration),
642
+ boolString (st->gotName), boolString (st->gotParenName));
643
+ printf ("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
644
+ printf ("access: %s default: %s\n", accessString (st->member.access),
645
+ accessString (st->member.accessDefault));
646
+ printf ("token : ");
647
+ pt (activeToken (st));
648
+ for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
649
+ {
650
+ printf ("prev %u : ", i);
651
+ pt (prevToken (st, i));
652
+ }
653
+ printf ("context: ");
654
+ pt (st->context);
655
+ }
656
+
657
+ #endif
658
+
659
+ /*
660
+ * Statement management
661
+ */
662
+
663
+ static boolean isContextualKeyword (const tokenInfo *const token)
664
+ {
665
+ boolean result;
666
+ switch (token->keyword)
667
+ {
668
+ case KEYWORD_CLASS:
669
+ case KEYWORD_ENUM:
670
+ case KEYWORD_INTERFACE:
671
+ case KEYWORD_NAMESPACE:
672
+ case KEYWORD_STRUCT:
673
+ case KEYWORD_UNION:
674
+ result = TRUE;
675
+ break;
676
+
677
+ default: result = FALSE; break;
678
+ }
679
+ return result;
680
+ }
681
+
682
+ static boolean isContextualStatement (const statementInfo *const st)
683
+ {
684
+ boolean result = FALSE;
685
+ if (st != NULL) switch (st->declaration)
686
+ {
687
+ case DECL_CLASS:
688
+ case DECL_ENUM:
689
+ case DECL_INTERFACE:
690
+ case DECL_NAMESPACE:
691
+ case DECL_STRUCT:
692
+ case DECL_UNION:
693
+ result = TRUE;
694
+ break;
695
+
696
+ default: result = FALSE; break;
697
+ }
698
+ return result;
699
+ }
700
+
701
+ static boolean isMember (const statementInfo *const st)
702
+ {
703
+ boolean result;
704
+ if (isType (st->context, TOKEN_NAME))
705
+ result = TRUE;
706
+ else
707
+ result = (boolean)
708
+ (st->parent != NULL && isContextualStatement (st->parent));
709
+ return result;
710
+ }
711
+
712
+ static void initMemberInfo (statementInfo *const st)
713
+ {
714
+ accessType accessDefault = ACCESS_UNDEFINED;
715
+
716
+ if (st->parent != NULL) switch (st->parent->declaration)
717
+ {
718
+ case DECL_ENUM:
719
+ accessDefault = (isLanguage (Lang_java) ? ACCESS_PUBLIC : ACCESS_UNDEFINED);
720
+ break;
721
+ case DECL_NAMESPACE:
722
+ accessDefault = ACCESS_UNDEFINED;
723
+ break;
724
+
725
+ case DECL_CLASS:
726
+ if (isLanguage (Lang_java))
727
+ accessDefault = ACCESS_DEFAULT;
728
+ else
729
+ accessDefault = ACCESS_PRIVATE;
730
+ break;
731
+
732
+ case DECL_INTERFACE:
733
+ case DECL_STRUCT:
734
+ case DECL_UNION:
735
+ accessDefault = ACCESS_PUBLIC;
736
+ break;
737
+
738
+ default: break;
739
+ }
740
+ st->member.accessDefault = accessDefault;
741
+ st->member.access = accessDefault;
742
+ }
743
+
744
+ static void reinitStatement (statementInfo *const st, const boolean partial)
745
+ {
746
+ unsigned int i;
747
+
748
+ if (! partial)
749
+ {
750
+ st->scope = SCOPE_GLOBAL;
751
+ if (isContextualStatement (st->parent))
752
+ st->declaration = DECL_BASE;
753
+ else
754
+ st->declaration = DECL_NONE;
755
+ }
756
+ st->gotParenName = FALSE;
757
+ st->isPointer = FALSE;
758
+ st->inFunction = FALSE;
759
+ st->assignment = FALSE;
760
+ st->notVariable = FALSE;
761
+ st->implementation = IMP_DEFAULT;
762
+ st->gotArgs = FALSE;
763
+ st->gotName = FALSE;
764
+ st->haveQualifyingName = FALSE;
765
+ st->tokenIndex = 0;
766
+
767
+ if (st->parent != NULL)
768
+ st->inFunction = st->parent->inFunction;
769
+
770
+ for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
771
+ initToken (st->token [i]);
772
+
773
+ initToken (st->context);
774
+
775
+ /* Keep the block name, so that a variable following after a comma will
776
+ * still have the structure name.
777
+ */
778
+ if (! partial)
779
+ initToken (st->blockName);
780
+
781
+ vStringClear (st->parentClasses);
782
+
783
+ /* Init member info.
784
+ */
785
+ if (! partial)
786
+ st->member.access = st->member.accessDefault;
787
+ }
788
+
789
+ static void initStatement (statementInfo *const st, statementInfo *const parent)
790
+ {
791
+ st->parent = parent;
792
+ initMemberInfo (st);
793
+ reinitStatement (st, FALSE);
794
+ }
795
+
796
+ /*
797
+ * Tag generation functions
798
+ */
799
+ static cKind cTagKind (const tagType type)
800
+ {
801
+ cKind result = CK_UNDEFINED;
802
+ switch (type)
803
+ {
804
+ case TAG_CLASS: result = CK_CLASS; break;
805
+ case TAG_ENUM: result = CK_ENUMERATION; break;
806
+ case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
807
+ case TAG_FUNCTION: result = CK_FUNCTION; break;
808
+ case TAG_LOCAL: result = CK_LOCAL; break;
809
+ case TAG_MEMBER: result = CK_MEMBER; break;
810
+ case TAG_NAMESPACE: result = CK_NAMESPACE; break;
811
+ case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
812
+ case TAG_STRUCT: result = CK_STRUCT; break;
813
+ case TAG_TYPEDEF: result = CK_TYPEDEF; break;
814
+ case TAG_UNION: result = CK_UNION; break;
815
+ case TAG_VARIABLE: result = CK_VARIABLE; break;
816
+ case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
817
+
818
+ default: Assert ("Bad C tag type" == NULL); break;
819
+ }
820
+ return result;
821
+ }
822
+
823
+ static csharpKind csharpTagKind (const tagType type)
824
+ {
825
+ csharpKind result = CSK_UNDEFINED;
826
+ switch (type)
827
+ {
828
+ case TAG_CLASS: result = CSK_CLASS; break;
829
+ case TAG_ENUM: result = CSK_ENUMERATION; break;
830
+ case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
831
+ case TAG_EVENT: result = CSK_EVENT; break;
832
+ case TAG_FIELD: result = CSK_FIELD ; break;
833
+ case TAG_INTERFACE: result = CSK_INTERFACE; break;
834
+ case TAG_LOCAL: result = CSK_LOCAL; break;
835
+ case TAG_METHOD: result = CSK_METHOD; break;
836
+ case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
837
+ case TAG_PROPERTY: result = CSK_PROPERTY; break;
838
+ case TAG_STRUCT: result = CSK_STRUCT; break;
839
+ case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
840
+
841
+ default: Assert ("Bad C# tag type" == NULL); break;
842
+ }
843
+ return result;
844
+ }
845
+
846
+ static javaKind javaTagKind (const tagType type)
847
+ {
848
+ javaKind result = JK_UNDEFINED;
849
+ switch (type)
850
+ {
851
+ case TAG_CLASS: result = JK_CLASS; break;
852
+ case TAG_ENUM: result = JK_ENUM; break;
853
+ case TAG_ENUMERATOR: result = JK_ENUM_CONSTANT; break;
854
+ case TAG_FIELD: result = JK_FIELD; break;
855
+ case TAG_INTERFACE: result = JK_INTERFACE; break;
856
+ case TAG_LOCAL: result = JK_LOCAL; break;
857
+ case TAG_METHOD: result = JK_METHOD; break;
858
+ case TAG_PACKAGE: result = JK_PACKAGE; break;
859
+
860
+ default: Assert ("Bad Java tag type" == NULL); break;
861
+ }
862
+ return result;
863
+ }
864
+
865
+ static veraKind veraTagKind (const tagType type) {
866
+ veraKind result = VK_UNDEFINED;
867
+ switch (type)
868
+ {
869
+ case TAG_CLASS: result = VK_CLASS; break;
870
+ case TAG_ENUM: result = VK_ENUMERATION; break;
871
+ case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
872
+ case TAG_FUNCTION: result = VK_FUNCTION; break;
873
+ case TAG_LOCAL: result = VK_LOCAL; break;
874
+ case TAG_MEMBER: result = VK_MEMBER; break;
875
+ case TAG_PROGRAM: result = VK_PROGRAM; break;
876
+ case TAG_PROTOTYPE: result = VK_PROTOTYPE; break;
877
+ case TAG_TASK: result = VK_TASK; break;
878
+ case TAG_TYPEDEF: result = VK_TYPEDEF; break;
879
+ case TAG_VARIABLE: result = VK_VARIABLE; break;
880
+ case TAG_EXTERN_VAR: result = VK_EXTERN_VARIABLE; break;
881
+
882
+ default: Assert ("Bad Vera tag type" == NULL); break;
883
+ }
884
+ return result;
885
+ }
886
+
887
+ static const char *tagName (const tagType type)
888
+ {
889
+ const char* result;
890
+ if (isLanguage (Lang_csharp))
891
+ result = CsharpKinds [csharpTagKind (type)].name;
892
+ else if (isLanguage (Lang_java))
893
+ result = JavaKinds [javaTagKind (type)].name;
894
+ else if (isLanguage (Lang_vera))
895
+ result = VeraKinds [veraTagKind (type)].name;
896
+ else
897
+ result = CKinds [cTagKind (type)].name;
898
+ return result;
899
+ }
900
+
901
+ static int tagLetter (const tagType type)
902
+ {
903
+ int result;
904
+ if (isLanguage (Lang_csharp))
905
+ result = CsharpKinds [csharpTagKind (type)].letter;
906
+ else if (isLanguage (Lang_java))
907
+ result = JavaKinds [javaTagKind (type)].letter;
908
+ else if (isLanguage (Lang_vera))
909
+ result = VeraKinds [veraTagKind (type)].letter;
910
+ else
911
+ result = CKinds [cTagKind (type)].letter;
912
+ return result;
913
+ }
914
+
915
+ static boolean includeTag (const tagType type, const boolean isFileScope)
916
+ {
917
+ boolean result;
918
+ if (isFileScope && ! Option.include.fileScope)
919
+ result = FALSE;
920
+ else if (isLanguage (Lang_csharp))
921
+ result = CsharpKinds [csharpTagKind (type)].enabled;
922
+ else if (isLanguage (Lang_java))
923
+ result = JavaKinds [javaTagKind (type)].enabled;
924
+ else if (isLanguage (Lang_vera))
925
+ result = VeraKinds [veraTagKind (type)].enabled;
926
+ else
927
+ result = CKinds [cTagKind (type)].enabled;
928
+ return result;
929
+ }
930
+
931
+ static tagType declToTagType (const declType declaration)
932
+ {
933
+ tagType type = TAG_UNDEFINED;
934
+
935
+ switch (declaration)
936
+ {
937
+ case DECL_CLASS: type = TAG_CLASS; break;
938
+ case DECL_ENUM: type = TAG_ENUM; break;
939
+ case DECL_EVENT: type = TAG_EVENT; break;
940
+ case DECL_FUNCTION: type = TAG_FUNCTION; break;
941
+ case DECL_INTERFACE: type = TAG_INTERFACE; break;
942
+ case DECL_NAMESPACE: type = TAG_NAMESPACE; break;
943
+ case DECL_PROGRAM: type = TAG_PROGRAM; break;
944
+ case DECL_TASK: type = TAG_TASK; break;
945
+ case DECL_STRUCT: type = TAG_STRUCT; break;
946
+ case DECL_UNION: type = TAG_UNION; break;
947
+
948
+ default: Assert ("Unexpected declaration" == NULL); break;
949
+ }
950
+ return type;
951
+ }
952
+
953
+ static const char* accessField (const statementInfo *const st)
954
+ {
955
+ const char* result = NULL;
956
+ if (isLanguage (Lang_cpp) && st->scope == SCOPE_FRIEND)
957
+ result = "friend";
958
+ else if (st->member.access != ACCESS_UNDEFINED)
959
+ result = accessString (st->member.access);
960
+ return result;
961
+ }
962
+
963
+ static void addContextSeparator (vString *const scope)
964
+ {
965
+ if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
966
+ vStringCatS (scope, "::");
967
+ else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
968
+ vStringCatS (scope, ".");
969
+ }
970
+
971
+ static void addOtherFields (tagEntryInfo* const tag, const tagType type,
972
+ const statementInfo *const st,
973
+ vString *const scope, vString *const typeRef)
974
+ {
975
+ /* For selected tag types, append an extension flag designating the
976
+ * parent object in which the tag is defined.
977
+ */
978
+ switch (type)
979
+ {
980
+ default: break;
981
+
982
+ case TAG_FUNCTION:
983
+ case TAG_METHOD:
984
+ case TAG_PROTOTYPE:
985
+ if (vStringLength (Signature) > 0)
986
+ tag->extensionFields.signature = vStringValue (Signature);
987
+ case TAG_CLASS:
988
+ case TAG_ENUM:
989
+ case TAG_ENUMERATOR:
990
+ case TAG_EVENT:
991
+ case TAG_FIELD:
992
+ case TAG_INTERFACE:
993
+ case TAG_MEMBER:
994
+ case TAG_NAMESPACE:
995
+ case TAG_PROPERTY:
996
+ case TAG_STRUCT:
997
+ case TAG_TASK:
998
+ case TAG_TYPEDEF:
999
+ case TAG_UNION:
1000
+ if (vStringLength (scope) > 0 &&
1001
+ (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1002
+ {
1003
+ if (isType (st->context, TOKEN_NAME))
1004
+ tag->extensionFields.scope [0] = tagName (TAG_CLASS);
1005
+ else
1006
+ tag->extensionFields.scope [0] =
1007
+ tagName (declToTagType (parentDecl (st)));
1008
+ tag->extensionFields.scope [1] = vStringValue (scope);
1009
+ }
1010
+ if ((type == TAG_CLASS || type == TAG_INTERFACE ||
1011
+ type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
1012
+ {
1013
+
1014
+ tag->extensionFields.inheritance =
1015
+ vStringValue (st->parentClasses);
1016
+ }
1017
+ if (st->implementation != IMP_DEFAULT &&
1018
+ (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) ||
1019
+ isLanguage (Lang_java)))
1020
+ {
1021
+ tag->extensionFields.implementation =
1022
+ implementationString (st->implementation);
1023
+ }
1024
+ if (isMember (st))
1025
+ {
1026
+ tag->extensionFields.access = accessField (st);
1027
+ }
1028
+ break;
1029
+ }
1030
+
1031
+ /* Add typename info, type of the tag and name of struct/union/etc. */
1032
+ if ((type == TAG_TYPEDEF || type == TAG_VARIABLE || type == TAG_MEMBER)
1033
+ && isContextualStatement(st))
1034
+ {
1035
+ char *p;
1036
+
1037
+ tag->extensionFields.typeRef [0] =
1038
+ tagName (declToTagType (st->declaration));
1039
+ p = vStringValue (st->blockName->name);
1040
+
1041
+ /* If there was no {} block get the name from the token before the
1042
+ * name (current token is ';' or ',', previous token is the name).
1043
+ */
1044
+ if (p == NULL || *p == '\0')
1045
+ {
1046
+ tokenInfo *const prev2 = prevToken (st, 2);
1047
+ if (isType (prev2, TOKEN_NAME))
1048
+ p = vStringValue (prev2->name);
1049
+ }
1050
+
1051
+ /* Prepend the scope name if there is one. */
1052
+ if (vStringLength (scope) > 0)
1053
+ {
1054
+ vStringCopy(typeRef, scope);
1055
+ addContextSeparator (typeRef);
1056
+ vStringCatS(typeRef, p);
1057
+ p = vStringValue (typeRef);
1058
+ }
1059
+ tag->extensionFields.typeRef [1] = p;
1060
+ }
1061
+ }
1062
+
1063
+ static void findScopeHierarchy (vString *const string,
1064
+ const statementInfo *const st)
1065
+ {
1066
+ vStringClear (string);
1067
+ if (isType (st->context, TOKEN_NAME))
1068
+ vStringCopy (string, st->context->name);
1069
+ if (st->parent != NULL)
1070
+ {
1071
+ vString *temp = vStringNew ();
1072
+ const statementInfo *s;
1073
+ for (s = st->parent ; s != NULL ; s = s->parent)
1074
+ {
1075
+ if (isContextualStatement (s) ||
1076
+ s->declaration == DECL_NAMESPACE ||
1077
+ s->declaration == DECL_PROGRAM)
1078
+ {
1079
+ vStringCopy (temp, string);
1080
+ vStringClear (string);
1081
+ Assert (isType (s->blockName, TOKEN_NAME));
1082
+ if (isType (s->context, TOKEN_NAME) &&
1083
+ vStringLength (s->context->name) > 0)
1084
+ {
1085
+ vStringCat (string, s->context->name);
1086
+ addContextSeparator (string);
1087
+ }
1088
+ vStringCat (string, s->blockName->name);
1089
+ if (vStringLength (temp) > 0)
1090
+ addContextSeparator (string);
1091
+ vStringCat (string, temp);
1092
+ }
1093
+ }
1094
+ vStringDelete (temp);
1095
+ }
1096
+ }
1097
+
1098
+ static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1099
+ vString *const scope)
1100
+ {
1101
+ if (Option.include.qualifiedTags &&
1102
+ scope != NULL && vStringLength (scope) > 0)
1103
+ {
1104
+ vString *const scopedName = vStringNew ();
1105
+
1106
+ if (type != TAG_ENUMERATOR)
1107
+ vStringCopy (scopedName, scope);
1108
+ else
1109
+ {
1110
+ /* remove last component (i.e. enumeration name) from scope */
1111
+ const char* const sc = vStringValue (scope);
1112
+ const char* colon = strrchr (sc, ':');
1113
+ if (colon != NULL)
1114
+ {
1115
+ while (*colon == ':' && colon > sc)
1116
+ --colon;
1117
+ vStringNCopy (scopedName, scope, colon + 1 - sc);
1118
+ }
1119
+ }
1120
+ if (vStringLength (scopedName) > 0)
1121
+ {
1122
+ addContextSeparator (scopedName);
1123
+ vStringCatS (scopedName, e->name);
1124
+ e->name = vStringValue (scopedName);
1125
+ makeTagEntry (e);
1126
+ }
1127
+ vStringDelete (scopedName);
1128
+ }
1129
+ }
1130
+
1131
+ static void makeTag (const tokenInfo *const token,
1132
+ const statementInfo *const st,
1133
+ boolean isFileScope, const tagType type)
1134
+ {
1135
+ /* Nothing is really of file scope when it appears in a header file.
1136
+ */
1137
+ isFileScope = (boolean) (isFileScope && ! isHeaderFile ());
1138
+
1139
+ if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 &&
1140
+ includeTag (type, isFileScope))
1141
+ {
1142
+ vString *scope = vStringNew ();
1143
+ /* Use "typeRef" to store the typename from addOtherFields() until
1144
+ * it's used in makeTagEntry().
1145
+ */
1146
+ vString *typeRef = vStringNew ();
1147
+ tagEntryInfo e;
1148
+
1149
+ initTagEntry (&e, vStringValue (token->name));
1150
+
1151
+ e.lineNumber = token->lineNumber;
1152
+ e.filePosition = token->filePosition;
1153
+ e.isFileScope = isFileScope;
1154
+ e.kindName = tagName (type);
1155
+ e.kind = tagLetter (type);
1156
+
1157
+ findScopeHierarchy (scope, st);
1158
+ addOtherFields (&e, type, st, scope, typeRef);
1159
+
1160
+ makeTagEntry (&e);
1161
+ makeExtraTagEntry (type, &e, scope);
1162
+ vStringDelete (scope);
1163
+ vStringDelete (typeRef);
1164
+ }
1165
+ }
1166
+
1167
+ static boolean isValidTypeSpecifier (const declType declaration)
1168
+ {
1169
+ boolean result;
1170
+ switch (declaration)
1171
+ {
1172
+ case DECL_BASE:
1173
+ case DECL_CLASS:
1174
+ case DECL_ENUM:
1175
+ case DECL_EVENT:
1176
+ case DECL_STRUCT:
1177
+ case DECL_UNION:
1178
+ result = TRUE;
1179
+ break;
1180
+
1181
+ default:
1182
+ result = FALSE;
1183
+ break;
1184
+ }
1185
+ return result;
1186
+ }
1187
+
1188
+ static void qualifyEnumeratorTag (const statementInfo *const st,
1189
+ const tokenInfo *const nameToken)
1190
+ {
1191
+ if (isType (nameToken, TOKEN_NAME))
1192
+ makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
1193
+ }
1194
+
1195
+ static void qualifyFunctionTag (const statementInfo *const st,
1196
+ const tokenInfo *const nameToken)
1197
+ {
1198
+ if (isType (nameToken, TOKEN_NAME))
1199
+ {
1200
+ tagType type;
1201
+ const boolean isFileScope =
1202
+ (boolean) (st->member.access == ACCESS_PRIVATE ||
1203
+ (!isMember (st) && st->scope == SCOPE_STATIC));
1204
+ if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
1205
+ type = TAG_METHOD;
1206
+ else if (isLanguage (Lang_vera) && st->declaration == DECL_TASK)
1207
+ type = TAG_TASK;
1208
+ else
1209
+ type = TAG_FUNCTION;
1210
+ makeTag (nameToken, st, isFileScope, type);
1211
+ }
1212
+ }
1213
+
1214
+ static void qualifyFunctionDeclTag (const statementInfo *const st,
1215
+ const tokenInfo *const nameToken)
1216
+ {
1217
+ if (! isType (nameToken, TOKEN_NAME))
1218
+ ;
1219
+ else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
1220
+ qualifyFunctionTag (st, nameToken);
1221
+ else if (st->scope == SCOPE_TYPEDEF)
1222
+ makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1223
+ else if (isValidTypeSpecifier (st->declaration) && ! isLanguage (Lang_csharp))
1224
+ makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
1225
+ }
1226
+
1227
+ static void qualifyCompoundTag (const statementInfo *const st,
1228
+ const tokenInfo *const nameToken)
1229
+ {
1230
+ if (isType (nameToken, TOKEN_NAME))
1231
+ {
1232
+ const tagType type = declToTagType (st->declaration);
1233
+ const boolean fileScoped = (boolean)
1234
+ (!(isLanguage (Lang_java) ||
1235
+ isLanguage (Lang_csharp) ||
1236
+ isLanguage (Lang_vera)));
1237
+
1238
+ if (type != TAG_UNDEFINED)
1239
+ makeTag (nameToken, st, fileScoped, type);
1240
+ }
1241
+ }
1242
+
1243
+ static void qualifyBlockTag (statementInfo *const st,
1244
+ const tokenInfo *const nameToken)
1245
+ {
1246
+ switch (st->declaration)
1247
+ {
1248
+ case DECL_CLASS:
1249
+ case DECL_ENUM:
1250
+ case DECL_INTERFACE:
1251
+ case DECL_NAMESPACE:
1252
+ case DECL_PROGRAM:
1253
+ case DECL_STRUCT:
1254
+ case DECL_UNION:
1255
+ qualifyCompoundTag (st, nameToken);
1256
+ break;
1257
+ default: break;
1258
+ }
1259
+ }
1260
+
1261
+ static void qualifyVariableTag (const statementInfo *const st,
1262
+ const tokenInfo *const nameToken)
1263
+ {
1264
+ /* We have to watch that we do not interpret a declaration of the
1265
+ * form "struct tag;" as a variable definition. In such a case, the
1266
+ * token preceding the name will be a keyword.
1267
+ */
1268
+ if (! isType (nameToken, TOKEN_NAME))
1269
+ ;
1270
+ else if (st->scope == SCOPE_TYPEDEF)
1271
+ makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1272
+ else if (st->declaration == DECL_EVENT)
1273
+ makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE),
1274
+ TAG_EVENT);
1275
+ else if (st->declaration == DECL_PACKAGE)
1276
+ makeTag (nameToken, st, FALSE, TAG_PACKAGE);
1277
+ else if (isValidTypeSpecifier (st->declaration))
1278
+ {
1279
+ if (st->notVariable)
1280
+ ;
1281
+ else if (isMember (st))
1282
+ {
1283
+ if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
1284
+ makeTag (nameToken, st,
1285
+ (boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1286
+ else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1287
+ makeTag (nameToken, st, TRUE, TAG_MEMBER);
1288
+ }
1289
+ else
1290
+ {
1291
+ if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1292
+ makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
1293
+ else if (st->inFunction)
1294
+ makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
1295
+ TAG_LOCAL);
1296
+ else
1297
+ makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
1298
+ TAG_VARIABLE);
1299
+ }
1300
+ }
1301
+ }
1302
+
1303
+ /*
1304
+ * Parsing functions
1305
+ */
1306
+
1307
+ static int skipToOneOf (const char *const chars)
1308
+ {
1309
+ int c;
1310
+ do
1311
+ c = cppGetc ();
1312
+ while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1313
+ return c;
1314
+ }
1315
+
1316
+ /* Skip to the next non-white character.
1317
+ */
1318
+ static int skipToNonWhite (void)
1319
+ {
1320
+ boolean found = FALSE;
1321
+ int c;
1322
+
1323
+ #if 0
1324
+ do
1325
+ c = cppGetc ();
1326
+ while (isspace (c));
1327
+ #else
1328
+ while (1)
1329
+ {
1330
+ c = cppGetc ();
1331
+ if (isspace (c))
1332
+ found = TRUE;
1333
+ else
1334
+ break;
1335
+ }
1336
+ if (CollectingSignature && found)
1337
+ vStringPut (Signature, ' ');
1338
+ #endif
1339
+
1340
+ return c;
1341
+ }
1342
+
1343
+ /* Skips to the next brace in column 1. This is intended for cases where
1344
+ * preprocessor constructs result in unbalanced braces.
1345
+ */
1346
+ static void skipToFormattedBraceMatch (void)
1347
+ {
1348
+ int c, next;
1349
+
1350
+ c = cppGetc ();
1351
+ next = cppGetc ();
1352
+ while (c != EOF && (c != '\n' || next != '}'))
1353
+ {
1354
+ c = next;
1355
+ next = cppGetc ();
1356
+ }
1357
+ }
1358
+
1359
+ /* Skip to the matching character indicated by the pair string. If skipping
1360
+ * to a matching brace and any brace is found within a different level of a
1361
+ * #if conditional statement while brace formatting is in effect, we skip to
1362
+ * the brace matched by its formatting. It is assumed that we have already
1363
+ * read the character which starts the group (i.e. the first character of
1364
+ * "pair").
1365
+ */
1366
+ static void skipToMatch (const char *const pair)
1367
+ {
1368
+ const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
1369
+ const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
1370
+ const unsigned int initialLevel = getDirectiveNestLevel ();
1371
+ const int begin = pair [0], end = pair [1];
1372
+ const unsigned long inputLineNumber = getInputLineNumber ();
1373
+ int matchLevel = 1;
1374
+ int c = '\0';
1375
+
1376
+ while (matchLevel > 0 && (c = skipToNonWhite ()) != EOF)
1377
+ {
1378
+ if (CollectingSignature)
1379
+ vStringPut (Signature, c);
1380
+ if (c == begin)
1381
+ {
1382
+ ++matchLevel;
1383
+ if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1384
+ {
1385
+ skipToFormattedBraceMatch ();
1386
+ break;
1387
+ }
1388
+ }
1389
+ else if (c == end)
1390
+ {
1391
+ --matchLevel;
1392
+ if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1393
+ {
1394
+ skipToFormattedBraceMatch ();
1395
+ break;
1396
+ }
1397
+ }
1398
+ }
1399
+ if (c == EOF)
1400
+ {
1401
+ verbose ("%s: failed to find match for '%c' at line %lu\n",
1402
+ getInputFileName (), begin, inputLineNumber);
1403
+ if (braceMatching)
1404
+ longjmp (Exception, (int) ExceptionBraceFormattingError);
1405
+ else
1406
+ longjmp (Exception, (int) ExceptionFormattingError);
1407
+ }
1408
+ }
1409
+
1410
+ static void skipParens (void)
1411
+ {
1412
+ const int c = skipToNonWhite ();
1413
+
1414
+ if (c == '(')
1415
+ skipToMatch ("()");
1416
+ else
1417
+ cppUngetc (c);
1418
+ }
1419
+
1420
+ static void skipBraces (void)
1421
+ {
1422
+ const int c = skipToNonWhite ();
1423
+
1424
+ if (c == '{')
1425
+ skipToMatch ("{}");
1426
+ else
1427
+ cppUngetc (c);
1428
+ }
1429
+
1430
+ static keywordId analyzeKeyword (const char *const name)
1431
+ {
1432
+ const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1433
+ return id;
1434
+ }
1435
+
1436
+ static void analyzeIdentifier (tokenInfo *const token)
1437
+ {
1438
+ char *const name = vStringValue (token->name);
1439
+ const char *replacement = NULL;
1440
+ boolean parensToo = FALSE;
1441
+
1442
+ if (isLanguage (Lang_java) ||
1443
+ ! isIgnoreToken (name, &parensToo, &replacement))
1444
+ {
1445
+ if (replacement != NULL)
1446
+ token->keyword = analyzeKeyword (replacement);
1447
+ else
1448
+ token->keyword = analyzeKeyword (vStringValue (token->name));
1449
+
1450
+ if (token->keyword == KEYWORD_NONE)
1451
+ token->type = TOKEN_NAME;
1452
+ else
1453
+ token->type = TOKEN_KEYWORD;
1454
+ }
1455
+ else
1456
+ {
1457
+ initToken (token);
1458
+ if (parensToo)
1459
+ {
1460
+ int c = skipToNonWhite ();
1461
+
1462
+ if (c == '(')
1463
+ skipToMatch ("()");
1464
+ }
1465
+ }
1466
+ }
1467
+
1468
+ static void readIdentifier (tokenInfo *const token, const int firstChar)
1469
+ {
1470
+ vString *const name = token->name;
1471
+ int c = firstChar;
1472
+ boolean first = TRUE;
1473
+
1474
+ initToken (token);
1475
+
1476
+ /* Bug #1585745: strangely, C++ destructors allow whitespace between
1477
+ * the ~ and the class name. */
1478
+ if (isLanguage (Lang_cpp) && firstChar == '~')
1479
+ {
1480
+ vStringPut (name, c);
1481
+ c = skipToNonWhite ();
1482
+ }
1483
+
1484
+ do
1485
+ {
1486
+ vStringPut (name, c);
1487
+ if (CollectingSignature)
1488
+ {
1489
+ if (!first)
1490
+ vStringPut (Signature, c);
1491
+ first = FALSE;
1492
+ }
1493
+ c = cppGetc ();
1494
+ } while (isident (c) || ((isLanguage (Lang_java) || isLanguage (Lang_csharp)) && (isHighChar (c) || c == '.')));
1495
+ vStringTerminate (name);
1496
+ cppUngetc (c); /* unget non-identifier character */
1497
+
1498
+ analyzeIdentifier (token);
1499
+ }
1500
+
1501
+ static void readPackageName (tokenInfo *const token, const int firstChar)
1502
+ {
1503
+ vString *const name = token->name;
1504
+ int c = firstChar;
1505
+
1506
+ initToken (token);
1507
+
1508
+ while (isident (c) || c == '.')
1509
+ {
1510
+ vStringPut (name, c);
1511
+ c = cppGetc ();
1512
+ }
1513
+ vStringTerminate (name);
1514
+ cppUngetc (c); /* unget non-package character */
1515
+ }
1516
+
1517
+ static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1518
+ {
1519
+ st->declaration = declaration;
1520
+
1521
+ if (declaration == DECL_NAMESPACE && !isLanguage (Lang_csharp))
1522
+ {
1523
+ /* In C++ a namespace is specified one level at a time. */
1524
+ return;
1525
+ }
1526
+ else
1527
+ {
1528
+ /* In C#, a namespace can also be specified like a Java package name. */
1529
+ tokenInfo *const token = activeToken (st);
1530
+ Assert (isType (token, TOKEN_KEYWORD));
1531
+ readPackageName (token, skipToNonWhite ());
1532
+ token->type = TOKEN_NAME;
1533
+ st->gotName = TRUE;
1534
+ st->haveQualifyingName = TRUE;
1535
+ }
1536
+ }
1537
+
1538
+ static void processName (statementInfo *const st)
1539
+ {
1540
+ Assert (isType (activeToken (st), TOKEN_NAME));
1541
+ if (st->gotName && st->declaration == DECL_NONE)
1542
+ st->declaration = DECL_BASE;
1543
+ st->gotName = TRUE;
1544
+ st->haveQualifyingName = TRUE;
1545
+ }
1546
+
1547
+ static void readOperator (statementInfo *const st)
1548
+ {
1549
+ const char *const acceptable = "+-*/%^&|~!=<>,[]";
1550
+ const tokenInfo* const prev = prevToken (st,1);
1551
+ tokenInfo *const token = activeToken (st);
1552
+ vString *const name = token->name;
1553
+ int c = skipToNonWhite ();
1554
+
1555
+ /* When we arrive here, we have the keyword "operator" in 'name'.
1556
+ */
1557
+ if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1558
+ prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1559
+ ; /* ignore "operator" keyword if preceded by these keywords */
1560
+ else if (c == '(')
1561
+ {
1562
+ /* Verify whether this is a valid function call (i.e. "()") operator.
1563
+ */
1564
+ if (cppGetc () == ')')
1565
+ {
1566
+ vStringPut (name, ' '); /* always separate operator from keyword */
1567
+ c = skipToNonWhite ();
1568
+ if (c == '(')
1569
+ vStringCatS (name, "()");
1570
+ }
1571
+ else
1572
+ {
1573
+ skipToMatch ("()");
1574
+ c = cppGetc ();
1575
+ }
1576
+ }
1577
+ else if (isident1 (c))
1578
+ {
1579
+ /* Handle "new" and "delete" operators, and conversion functions
1580
+ * (per 13.3.1.1.2 [2] of the C++ spec).
1581
+ */
1582
+ boolean whiteSpace = TRUE; /* default causes insertion of space */
1583
+ do
1584
+ {
1585
+ if (isspace (c))
1586
+ whiteSpace = TRUE;
1587
+ else
1588
+ {
1589
+ if (whiteSpace)
1590
+ {
1591
+ vStringPut (name, ' ');
1592
+ whiteSpace = FALSE;
1593
+ }
1594
+ vStringPut (name, c);
1595
+ }
1596
+ c = cppGetc ();
1597
+ } while (! isOneOf (c, "(;") && c != EOF);
1598
+ vStringTerminate (name);
1599
+ }
1600
+ else if (isOneOf (c, acceptable))
1601
+ {
1602
+ vStringPut (name, ' '); /* always separate operator from keyword */
1603
+ do
1604
+ {
1605
+ vStringPut (name, c);
1606
+ c = cppGetc ();
1607
+ } while (isOneOf (c, acceptable));
1608
+ vStringTerminate (name);
1609
+ }
1610
+
1611
+ cppUngetc (c);
1612
+
1613
+ token->type = TOKEN_NAME;
1614
+ token->keyword = KEYWORD_NONE;
1615
+ processName (st);
1616
+ }
1617
+
1618
+ static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1619
+ {
1620
+ dest->type = src->type;
1621
+ dest->keyword = src->keyword;
1622
+ dest->filePosition = src->filePosition;
1623
+ dest->lineNumber = src->lineNumber;
1624
+ vStringCopy (dest->name, src->name);
1625
+ }
1626
+
1627
+ static void setAccess (statementInfo *const st, const accessType access)
1628
+ {
1629
+ if (isMember (st))
1630
+ {
1631
+ if (isLanguage (Lang_cpp))
1632
+ {
1633
+ int c = skipToNonWhite ();
1634
+
1635
+ if (c == ':')
1636
+ reinitStatement (st, FALSE);
1637
+ else
1638
+ cppUngetc (c);
1639
+
1640
+ st->member.accessDefault = access;
1641
+ }
1642
+ st->member.access = access;
1643
+ }
1644
+ }
1645
+
1646
+ static void discardTypeList (tokenInfo *const token)
1647
+ {
1648
+ int c = skipToNonWhite ();
1649
+ while (isident1 (c))
1650
+ {
1651
+ readIdentifier (token, c);
1652
+ c = skipToNonWhite ();
1653
+ if (c == '.' || c == ',')
1654
+ c = skipToNonWhite ();
1655
+ }
1656
+ cppUngetc (c);
1657
+ }
1658
+
1659
+ static void addParentClass (statementInfo *const st, tokenInfo *const token)
1660
+ {
1661
+ if (vStringLength (token->name) > 0 &&
1662
+ vStringLength (st->parentClasses) > 0)
1663
+ {
1664
+ vStringPut (st->parentClasses, ',');
1665
+ }
1666
+ vStringCat (st->parentClasses, token->name);
1667
+ }
1668
+
1669
+ static void readParents (statementInfo *const st, const int qualifier)
1670
+ {
1671
+ tokenInfo *const token = newToken ();
1672
+ tokenInfo *const parent = newToken ();
1673
+ int c;
1674
+
1675
+ do
1676
+ {
1677
+ c = skipToNonWhite ();
1678
+ if (isident1 (c))
1679
+ {
1680
+ readIdentifier (token, c);
1681
+ if (isType (token, TOKEN_NAME))
1682
+ vStringCat (parent->name, token->name);
1683
+ else
1684
+ {
1685
+ addParentClass (st, parent);
1686
+ initToken (parent);
1687
+ }
1688
+ }
1689
+ else if (c == qualifier)
1690
+ vStringPut (parent->name, c);
1691
+ else if (c == '<')
1692
+ skipToMatch ("<>");
1693
+ else if (isType (token, TOKEN_NAME))
1694
+ {
1695
+ addParentClass (st, parent);
1696
+ initToken (parent);
1697
+ }
1698
+ } while (c != '{' && c != EOF);
1699
+ cppUngetc (c);
1700
+ deleteToken (parent);
1701
+ deleteToken (token);
1702
+ }
1703
+
1704
+ static void skipStatement (statementInfo *const st)
1705
+ {
1706
+ st->declaration = DECL_IGNORE;
1707
+ skipToOneOf (";");
1708
+ }
1709
+
1710
+ static void processInterface (statementInfo *const st)
1711
+ {
1712
+ st->declaration = DECL_INTERFACE;
1713
+ }
1714
+
1715
+ static void processToken (tokenInfo *const token, statementInfo *const st)
1716
+ {
1717
+ switch (token->keyword) /* is it a reserved word? */
1718
+ {
1719
+ default: break;
1720
+
1721
+ case KEYWORD_NONE: processName (st); break;
1722
+ case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
1723
+ case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
1724
+ case KEYWORD_BIND: st->declaration = DECL_BASE; break;
1725
+ case KEYWORD_BIT: st->declaration = DECL_BASE; break;
1726
+ case KEYWORD_CATCH: skipParens (); skipBraces (); break;
1727
+ case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
1728
+ case KEYWORD_CLASS: st->declaration = DECL_CLASS; break;
1729
+ case KEYWORD_CONST: st->declaration = DECL_BASE; break;
1730
+ case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
1731
+ case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
1732
+ case KEYWORD_EXTENDS: readParents (st, '.');
1733
+ setToken (st, TOKEN_NONE); break;
1734
+ case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
1735
+ case KEYWORD_FUNCTION: st->declaration = DECL_BASE; break;
1736
+ case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
1737
+ case KEYWORD_GOTO: skipStatement (st); break;
1738
+ case KEYWORD_IMPLEMENTS:readParents (st, '.');
1739
+ setToken (st, TOKEN_NONE); break;
1740
+ case KEYWORD_IMPORT: skipStatement (st); break;
1741
+ case KEYWORD_INT: st->declaration = DECL_BASE; break;
1742
+ case KEYWORD_INTEGER: st->declaration = DECL_BASE; break;
1743
+ case KEYWORD_INTERFACE: processInterface (st); break;
1744
+ case KEYWORD_LOCAL: setAccess (st, ACCESS_LOCAL); break;
1745
+ case KEYWORD_LONG: st->declaration = DECL_BASE; break;
1746
+ case KEYWORD_OPERATOR: readOperator (st); break;
1747
+ case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
1748
+ case KEYWORD_PROGRAM: st->declaration = DECL_PROGRAM; break;
1749
+ case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
1750
+ case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
1751
+ case KEYWORD_RETURN: skipStatement (st); break;
1752
+ case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
1753
+ case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
1754
+ case KEYWORD_STRING: st->declaration = DECL_BASE; break;
1755
+ case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break;
1756
+ case KEYWORD_TASK: st->declaration = DECL_TASK; break;
1757
+ case KEYWORD_THROWS: discardTypeList (token); break;
1758
+ case KEYWORD_UNION: st->declaration = DECL_UNION; break;
1759
+ case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
1760
+ case KEYWORD_USING: skipStatement (st); break;
1761
+ case KEYWORD_VOID: st->declaration = DECL_BASE; break;
1762
+ case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
1763
+ case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
1764
+ case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
1765
+
1766
+ case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
1767
+ case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
1768
+
1769
+ case KEYWORD_EVENT:
1770
+ if (isLanguage (Lang_csharp))
1771
+ st->declaration = DECL_EVENT;
1772
+ break;
1773
+
1774
+ case KEYWORD_TYPEDEF:
1775
+ reinitStatement (st, FALSE);
1776
+ st->scope = SCOPE_TYPEDEF;
1777
+ break;
1778
+
1779
+ case KEYWORD_EXTERN:
1780
+ if (! isLanguage (Lang_csharp) || !st->gotName)
1781
+ {
1782
+ reinitStatement (st, FALSE);
1783
+ st->scope = SCOPE_EXTERN;
1784
+ st->declaration = DECL_BASE;
1785
+ }
1786
+ break;
1787
+
1788
+ case KEYWORD_STATIC:
1789
+ if (! (isLanguage (Lang_java) || isLanguage (Lang_csharp)))
1790
+ {
1791
+ reinitStatement (st, FALSE);
1792
+ st->scope = SCOPE_STATIC;
1793
+ st->declaration = DECL_BASE;
1794
+ }
1795
+ break;
1796
+
1797
+ case KEYWORD_FOR:
1798
+ case KEYWORD_FOREACH:
1799
+ case KEYWORD_IF:
1800
+ case KEYWORD_SWITCH:
1801
+ case KEYWORD_WHILE:
1802
+ {
1803
+ int c = skipToNonWhite ();
1804
+ if (c == '(')
1805
+ skipToMatch ("()");
1806
+ break;
1807
+ }
1808
+ }
1809
+ }
1810
+
1811
+ /*
1812
+ * Parenthesis handling functions
1813
+ */
1814
+
1815
+ static void restartStatement (statementInfo *const st)
1816
+ {
1817
+ tokenInfo *const save = newToken ();
1818
+ tokenInfo *token = activeToken (st);
1819
+
1820
+ copyToken (save, token);
1821
+ DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
1822
+ reinitStatement (st, FALSE);
1823
+ token = activeToken (st);
1824
+ copyToken (token, save);
1825
+ deleteToken (save);
1826
+ processToken (token, st);
1827
+ }
1828
+
1829
+ /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
1830
+ *
1831
+ * mem-initializer-list:
1832
+ * mem-initializer, mem-initializer-list
1833
+ *
1834
+ * mem-initializer:
1835
+ * [::] [nested-name-spec] class-name (...)
1836
+ * identifier
1837
+ */
1838
+ static void skipMemIntializerList (tokenInfo *const token)
1839
+ {
1840
+ int c;
1841
+
1842
+ do
1843
+ {
1844
+ c = skipToNonWhite ();
1845
+ while (isident1 (c) || c == ':')
1846
+ {
1847
+ if (c != ':')
1848
+ readIdentifier (token, c);
1849
+ c = skipToNonWhite ();
1850
+ }
1851
+ if (c == '<')
1852
+ {
1853
+ skipToMatch ("<>");
1854
+ c = skipToNonWhite ();
1855
+ }
1856
+ if (c == '(')
1857
+ {
1858
+ skipToMatch ("()");
1859
+ c = skipToNonWhite ();
1860
+ }
1861
+ } while (c == ',');
1862
+ cppUngetc (c);
1863
+ }
1864
+
1865
+ static void skipMacro (statementInfo *const st)
1866
+ {
1867
+ tokenInfo *const prev2 = prevToken (st, 2);
1868
+
1869
+ if (isType (prev2, TOKEN_NAME))
1870
+ retardToken (st);
1871
+ skipToMatch ("()");
1872
+ }
1873
+
1874
+ /* Skips over characters following the parameter list. This will be either
1875
+ * non-ANSI style function declarations or C++ stuff. Our choices:
1876
+ *
1877
+ * C (K&R):
1878
+ * int func ();
1879
+ * int func (one, two) int one; float two; {...}
1880
+ * C (ANSI):
1881
+ * int func (int one, float two);
1882
+ * int func (int one, float two) {...}
1883
+ * C++:
1884
+ * int foo (...) [const|volatile] [throw (...)];
1885
+ * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
1886
+ * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
1887
+ * catch (...) {...}
1888
+ */
1889
+ static boolean skipPostArgumentStuff (
1890
+ statementInfo *const st, parenInfo *const info)
1891
+ {
1892
+ tokenInfo *const token = activeToken (st);
1893
+ unsigned int parameters = info->parameterCount;
1894
+ unsigned int elementCount = 0;
1895
+ boolean restart = FALSE;
1896
+ boolean end = FALSE;
1897
+ int c = skipToNonWhite ();
1898
+
1899
+ do
1900
+ {
1901
+ switch (c)
1902
+ {
1903
+ case ')': break;
1904
+ case ':': skipMemIntializerList (token);break; /* ctor-initializer */
1905
+ case '[': skipToMatch ("[]"); break;
1906
+ case '=': cppUngetc (c); end = TRUE; break;
1907
+ case '{': cppUngetc (c); end = TRUE; break;
1908
+ case '}': cppUngetc (c); end = TRUE; break;
1909
+
1910
+ case '(':
1911
+ if (elementCount > 0)
1912
+ ++elementCount;
1913
+ skipToMatch ("()");
1914
+ break;
1915
+
1916
+ case ';':
1917
+ if (parameters == 0 || elementCount < 2)
1918
+ {
1919
+ cppUngetc (c);
1920
+ end = TRUE;
1921
+ }
1922
+ else if (--parameters == 0)
1923
+ end = TRUE;
1924
+ break;
1925
+
1926
+ default:
1927
+ if (isident1 (c))
1928
+ {
1929
+ readIdentifier (token, c);
1930
+ switch (token->keyword)
1931
+ {
1932
+ case KEYWORD_ATTRIBUTE: skipParens (); break;
1933
+ case KEYWORD_THROW: skipParens (); break;
1934
+ case KEYWORD_TRY: break;
1935
+
1936
+ case KEYWORD_CONST:
1937
+ case KEYWORD_VOLATILE:
1938
+ if (vStringLength (Signature) > 0)
1939
+ {
1940
+ vStringPut (Signature, ' ');
1941
+ vStringCat (Signature, token->name);
1942
+ }
1943
+ break;
1944
+
1945
+ case KEYWORD_CATCH:
1946
+ case KEYWORD_CLASS:
1947
+ case KEYWORD_EXPLICIT:
1948
+ case KEYWORD_EXTERN:
1949
+ case KEYWORD_FRIEND:
1950
+ case KEYWORD_INLINE:
1951
+ case KEYWORD_MUTABLE:
1952
+ case KEYWORD_NAMESPACE:
1953
+ case KEYWORD_NEW:
1954
+ case KEYWORD_NEWCOV:
1955
+ case KEYWORD_OPERATOR:
1956
+ case KEYWORD_OVERLOAD:
1957
+ case KEYWORD_PRIVATE:
1958
+ case KEYWORD_PROTECTED:
1959
+ case KEYWORD_PUBLIC:
1960
+ case KEYWORD_STATIC:
1961
+ case KEYWORD_TEMPLATE:
1962
+ case KEYWORD_TYPEDEF:
1963
+ case KEYWORD_TYPENAME:
1964
+ case KEYWORD_USING:
1965
+ case KEYWORD_VIRTUAL:
1966
+ /* Never allowed within parameter declarations. */
1967
+ restart = TRUE;
1968
+ end = TRUE;
1969
+ break;
1970
+
1971
+ default:
1972
+ if (isType (token, TOKEN_NONE))
1973
+ ;
1974
+ else if (info->isKnrParamList && info->parameterCount > 0)
1975
+ ++elementCount;
1976
+ else
1977
+ {
1978
+ /* If we encounter any other identifier immediately
1979
+ * following an empty parameter list, this is almost
1980
+ * certainly one of those Microsoft macro "thingies"
1981
+ * that the automatic source code generation sticks
1982
+ * in. Terminate the current statement.
1983
+ */
1984
+ restart = TRUE;
1985
+ end = TRUE;
1986
+ }
1987
+ break;
1988
+ }
1989
+ }
1990
+ }
1991
+ if (! end)
1992
+ {
1993
+ c = skipToNonWhite ();
1994
+ if (c == EOF)
1995
+ end = TRUE;
1996
+ }
1997
+ } while (! end);
1998
+
1999
+ if (restart)
2000
+ restartStatement (st);
2001
+ else
2002
+ setToken (st, TOKEN_NONE);
2003
+
2004
+ return (boolean) (c != EOF);
2005
+ }
2006
+
2007
+ static void skipJavaThrows (statementInfo *const st)
2008
+ {
2009
+ tokenInfo *const token = activeToken (st);
2010
+ int c = skipToNonWhite ();
2011
+
2012
+ if (isident1 (c))
2013
+ {
2014
+ readIdentifier (token, c);
2015
+ if (token->keyword == KEYWORD_THROWS)
2016
+ {
2017
+ do
2018
+ {
2019
+ c = skipToNonWhite ();
2020
+ if (isident1 (c))
2021
+ {
2022
+ readIdentifier (token, c);
2023
+ c = skipToNonWhite ();
2024
+ }
2025
+ } while (c == '.' || c == ',');
2026
+ }
2027
+ }
2028
+ cppUngetc (c);
2029
+ setToken (st, TOKEN_NONE);
2030
+ }
2031
+
2032
+ static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2033
+ {
2034
+ const unsigned long inputLineNumber = getInputLineNumber ();
2035
+ int c = skipToNonWhite ();
2036
+
2037
+ cppUngetc (c);
2038
+ if (isOneOf (c, "{;,="))
2039
+ ;
2040
+ else if (isLanguage (Lang_java))
2041
+ skipJavaThrows (st);
2042
+ else
2043
+ {
2044
+ if (! skipPostArgumentStuff (st, info))
2045
+ {
2046
+ verbose (
2047
+ "%s: confusing argument declarations beginning at line %lu\n",
2048
+ getInputFileName (), inputLineNumber);
2049
+ longjmp (Exception, (int) ExceptionFormattingError);
2050
+ }
2051
+ }
2052
+ }
2053
+
2054
+ static boolean languageSupportsGenerics (void)
2055
+ {
2056
+ return (boolean) (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) ||
2057
+ isLanguage (Lang_java));
2058
+ }
2059
+
2060
+ static void processAngleBracket (void)
2061
+ {
2062
+ int c = cppGetc ();
2063
+ if (c == '>') {
2064
+ /* already found match for template */
2065
+ } else if (languageSupportsGenerics () && c != '<' && c != '=') {
2066
+ /* this is a template */
2067
+ cppUngetc (c);
2068
+ skipToMatch ("<>");
2069
+ } else if (c == '<') {
2070
+ /* skip "<<" or "<<=". */
2071
+ c = cppGetc ();
2072
+ if (c != '=') {
2073
+ cppUngetc (c);
2074
+ }
2075
+ } else {
2076
+ cppUngetc (c);
2077
+ }
2078
+ }
2079
+
2080
+ static void parseJavaAnnotation (statementInfo *const st)
2081
+ {
2082
+ /*
2083
+ * @Override
2084
+ * @Target(ElementType.METHOD)
2085
+ * @SuppressWarnings(value = "unchecked")
2086
+ *
2087
+ * But watch out for "@interface"!
2088
+ */
2089
+ tokenInfo *const token = activeToken (st);
2090
+
2091
+ int c = skipToNonWhite ();
2092
+ readIdentifier (token, c);
2093
+ if (token->keyword == KEYWORD_INTERFACE)
2094
+ {
2095
+ /* Oops. This was actually "@interface" defining a new annotation. */
2096
+ processInterface (st);
2097
+ }
2098
+ else
2099
+ {
2100
+ /* Bug #1691412: skip any annotation arguments. */
2101
+ skipParens ();
2102
+ }
2103
+ }
2104
+
2105
+ static int parseParens (statementInfo *const st, parenInfo *const info)
2106
+ {
2107
+ tokenInfo *const token = activeToken (st);
2108
+ unsigned int identifierCount = 0;
2109
+ unsigned int depth = 1;
2110
+ boolean firstChar = TRUE;
2111
+ int nextChar = '\0';
2112
+
2113
+ CollectingSignature = TRUE;
2114
+ vStringClear (Signature);
2115
+ vStringPut (Signature, '(');
2116
+ info->parameterCount = 1;
2117
+ do
2118
+ {
2119
+ int c = skipToNonWhite ();
2120
+ vStringPut (Signature, c);
2121
+
2122
+ switch (c)
2123
+ {
2124
+ case '&':
2125
+ case '*':
2126
+ info->isPointer = TRUE;
2127
+ info->isKnrParamList = FALSE;
2128
+ if (identifierCount == 0)
2129
+ info->isParamList = FALSE;
2130
+ initToken (token);
2131
+ break;
2132
+
2133
+ case ':':
2134
+ info->isKnrParamList = FALSE;
2135
+ break;
2136
+
2137
+ case '.':
2138
+ info->isNameCandidate = FALSE;
2139
+ c = cppGetc ();
2140
+ if (c != '.')
2141
+ {
2142
+ cppUngetc (c);
2143
+ info->isKnrParamList = FALSE;
2144
+ }
2145
+ else
2146
+ {
2147
+ c = cppGetc ();
2148
+ if (c != '.')
2149
+ {
2150
+ cppUngetc (c);
2151
+ info->isKnrParamList = FALSE;
2152
+ }
2153
+ else
2154
+ vStringCatS (Signature, "..."); /* variable arg list */
2155
+ }
2156
+ break;
2157
+
2158
+ case ',':
2159
+ info->isNameCandidate = FALSE;
2160
+ if (info->isKnrParamList)
2161
+ {
2162
+ ++info->parameterCount;
2163
+ identifierCount = 0;
2164
+ }
2165
+ break;
2166
+
2167
+ case '=':
2168
+ info->isKnrParamList = FALSE;
2169
+ info->isNameCandidate = FALSE;
2170
+ if (firstChar)
2171
+ {
2172
+ info->isParamList = FALSE;
2173
+ skipMacro (st);
2174
+ depth = 0;
2175
+ }
2176
+ break;
2177
+
2178
+ case '[':
2179
+ info->isKnrParamList = FALSE;
2180
+ skipToMatch ("[]");
2181
+ break;
2182
+
2183
+ case '<':
2184
+ info->isKnrParamList = FALSE;
2185
+ processAngleBracket ();
2186
+ break;
2187
+
2188
+ case ')':
2189
+ if (firstChar)
2190
+ info->parameterCount = 0;
2191
+ --depth;
2192
+ break;
2193
+
2194
+ case '(':
2195
+ info->isKnrParamList = FALSE;
2196
+ if (firstChar)
2197
+ {
2198
+ info->isNameCandidate = FALSE;
2199
+ cppUngetc (c);
2200
+ vStringClear (Signature);
2201
+ skipMacro (st);
2202
+ depth = 0;
2203
+ vStringChop (Signature);
2204
+ }
2205
+ else if (isType (token, TOKEN_PAREN_NAME))
2206
+ {
2207
+ c = skipToNonWhite ();
2208
+ if (c == '*') /* check for function pointer */
2209
+ {
2210
+ skipToMatch ("()");
2211
+ c = skipToNonWhite ();
2212
+ if (c == '(')
2213
+ skipToMatch ("()");
2214
+ else
2215
+ cppUngetc (c);
2216
+ }
2217
+ else
2218
+ {
2219
+ cppUngetc (c);
2220
+ cppUngetc ('(');
2221
+ info->nestedArgs = TRUE;
2222
+ }
2223
+ }
2224
+ else
2225
+ ++depth;
2226
+ break;
2227
+
2228
+ default:
2229
+ if (c == '@' && isLanguage (Lang_java))
2230
+ {
2231
+ parseJavaAnnotation(st);
2232
+ }
2233
+ else if (isident1 (c))
2234
+ {
2235
+ if (++identifierCount > 1)
2236
+ info->isKnrParamList = FALSE;
2237
+ readIdentifier (token, c);
2238
+ if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2239
+ token->type = TOKEN_PAREN_NAME;
2240
+ else if (isType (token, TOKEN_KEYWORD))
2241
+ {
2242
+ if (token->keyword != KEYWORD_CONST &&
2243
+ token->keyword != KEYWORD_VOLATILE)
2244
+ {
2245
+ info->isKnrParamList = FALSE;
2246
+ info->isNameCandidate = FALSE;
2247
+ }
2248
+ }
2249
+ }
2250
+ else
2251
+ {
2252
+ info->isParamList = FALSE;
2253
+ info->isKnrParamList = FALSE;
2254
+ info->isNameCandidate = FALSE;
2255
+ info->invalidContents = TRUE;
2256
+ }
2257
+ break;
2258
+ }
2259
+ firstChar = FALSE;
2260
+ } while (! info->nestedArgs && depth > 0 &&
2261
+ (info->isKnrParamList || info->isNameCandidate));
2262
+
2263
+ if (! info->nestedArgs) while (depth > 0)
2264
+ {
2265
+ skipToMatch ("()");
2266
+ --depth;
2267
+ }
2268
+
2269
+ if (! info->isNameCandidate)
2270
+ initToken (token);
2271
+
2272
+ vStringTerminate (Signature);
2273
+ if (info->isKnrParamList)
2274
+ vStringClear (Signature);
2275
+ CollectingSignature = FALSE;
2276
+ return nextChar;
2277
+ }
2278
+
2279
+ static void initParenInfo (parenInfo *const info)
2280
+ {
2281
+ info->isPointer = FALSE;
2282
+ info->isParamList = TRUE;
2283
+ info->isKnrParamList = isLanguage (Lang_c);
2284
+ info->isNameCandidate = TRUE;
2285
+ info->invalidContents = FALSE;
2286
+ info->nestedArgs = FALSE;
2287
+ info->parameterCount = 0;
2288
+ }
2289
+
2290
+ static void analyzeParens (statementInfo *const st)
2291
+ {
2292
+ tokenInfo *const prev = prevToken (st, 1);
2293
+
2294
+ if (st->inFunction && ! st->assignment)
2295
+ st->notVariable = TRUE;
2296
+ if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2297
+ {
2298
+ tokenInfo *const token = activeToken (st);
2299
+ parenInfo info;
2300
+ int c;
2301
+
2302
+ initParenInfo (&info);
2303
+ parseParens (st, &info);
2304
+ c = skipToNonWhite ();
2305
+ cppUngetc (c);
2306
+ if (info.invalidContents)
2307
+ reinitStatement (st, FALSE);
2308
+ else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2309
+ ! st->gotParenName &&
2310
+ (! info.isParamList || ! st->haveQualifyingName ||
2311
+ c == '(' ||
2312
+ (c == '=' && st->implementation != IMP_VIRTUAL) ||
2313
+ (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2314
+ {
2315
+ token->type = TOKEN_NAME;
2316
+ processName (st);
2317
+ st->gotParenName = TRUE;
2318
+ if (! (c == '(' && info.nestedArgs))
2319
+ st->isPointer = info.isPointer;
2320
+ }
2321
+ else if (! st->gotArgs && info.isParamList)
2322
+ {
2323
+ st->gotArgs = TRUE;
2324
+ setToken (st, TOKEN_ARGS);
2325
+ advanceToken (st);
2326
+ if (st->scope != SCOPE_TYPEDEF)
2327
+ analyzePostParens (st, &info);
2328
+ }
2329
+ else
2330
+ setToken (st, TOKEN_NONE);
2331
+ }
2332
+ }
2333
+
2334
+ /*
2335
+ * Token parsing functions
2336
+ */
2337
+
2338
+ static void addContext (statementInfo *const st, const tokenInfo* const token)
2339
+ {
2340
+ if (isType (token, TOKEN_NAME))
2341
+ {
2342
+ if (vStringLength (st->context->name) > 0)
2343
+ {
2344
+ if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
2345
+ vStringCatS (st->context->name, "::");
2346
+ else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
2347
+ vStringCatS (st->context->name, ".");
2348
+ }
2349
+ vStringCat (st->context->name, token->name);
2350
+ st->context->type = TOKEN_NAME;
2351
+ }
2352
+ }
2353
+
2354
+ static boolean inheritingDeclaration (declType decl)
2355
+ {
2356
+ /* C# supports inheritance for enums. C++0x will too, but not yet. */
2357
+ if (decl == DECL_ENUM)
2358
+ {
2359
+ return (boolean) (isLanguage (Lang_csharp));
2360
+ }
2361
+ return (boolean) (
2362
+ decl == DECL_CLASS ||
2363
+ decl == DECL_STRUCT ||
2364
+ decl == DECL_INTERFACE);
2365
+ }
2366
+
2367
+ static void processColon (statementInfo *const st)
2368
+ {
2369
+ int c = (isLanguage (Lang_cpp) ? cppGetc () : skipToNonWhite ());
2370
+ const boolean doubleColon = (boolean) (c == ':');
2371
+
2372
+ if (doubleColon)
2373
+ {
2374
+ setToken (st, TOKEN_DOUBLE_COLON);
2375
+ st->haveQualifyingName = FALSE;
2376
+ }
2377
+ else
2378
+ {
2379
+ cppUngetc (c);
2380
+ if ((isLanguage (Lang_cpp) || isLanguage (Lang_csharp)) &&
2381
+ inheritingDeclaration (st->declaration))
2382
+ {
2383
+ readParents (st, ':');
2384
+ }
2385
+ else if (parentDecl (st) == DECL_STRUCT)
2386
+ {
2387
+ c = skipToOneOf (",;");
2388
+ if (c == ',')
2389
+ setToken (st, TOKEN_COMMA);
2390
+ else if (c == ';')
2391
+ setToken (st, TOKEN_SEMICOLON);
2392
+ }
2393
+ else
2394
+ {
2395
+ const tokenInfo *const prev = prevToken (st, 1);
2396
+ const tokenInfo *const prev2 = prevToken (st, 2);
2397
+ if (prev->keyword == KEYWORD_DEFAULT ||
2398
+ prev2->keyword == KEYWORD_CASE ||
2399
+ st->parent != NULL)
2400
+ {
2401
+ reinitStatement (st, FALSE);
2402
+ }
2403
+ }
2404
+ }
2405
+ }
2406
+
2407
+ /* Skips over any initializing value which may follow an '=' character in a
2408
+ * variable definition.
2409
+ */
2410
+ static int skipInitializer (statementInfo *const st)
2411
+ {
2412
+ boolean done = FALSE;
2413
+ int c;
2414
+
2415
+ while (! done)
2416
+ {
2417
+ c = skipToNonWhite ();
2418
+
2419
+ if (c == EOF)
2420
+ longjmp (Exception, (int) ExceptionFormattingError);
2421
+ else switch (c)
2422
+ {
2423
+ case ',':
2424
+ case ';': done = TRUE; break;
2425
+
2426
+ case '0':
2427
+ if (st->implementation == IMP_VIRTUAL)
2428
+ st->implementation = IMP_PURE_VIRTUAL;
2429
+ break;
2430
+
2431
+ case '[': skipToMatch ("[]"); break;
2432
+ case '(': skipToMatch ("()"); break;
2433
+ case '{': skipToMatch ("{}"); break;
2434
+ case '<': processAngleBracket(); break;
2435
+
2436
+ case '}':
2437
+ if (insideEnumBody (st))
2438
+ done = TRUE;
2439
+ else if (! isBraceFormat ())
2440
+ {
2441
+ verbose ("%s: unexpected closing brace at line %lu\n",
2442
+ getInputFileName (), getInputLineNumber ());
2443
+ longjmp (Exception, (int) ExceptionBraceFormattingError);
2444
+ }
2445
+ break;
2446
+
2447
+ default: break;
2448
+ }
2449
+ }
2450
+ return c;
2451
+ }
2452
+
2453
+ static void processInitializer (statementInfo *const st)
2454
+ {
2455
+ const boolean inEnumBody = insideEnumBody (st);
2456
+ int c = cppGetc ();
2457
+
2458
+ if (c != '=')
2459
+ {
2460
+ cppUngetc (c);
2461
+ c = skipInitializer (st);
2462
+ st->assignment = TRUE;
2463
+ if (c == ';')
2464
+ setToken (st, TOKEN_SEMICOLON);
2465
+ else if (c == ',')
2466
+ setToken (st, TOKEN_COMMA);
2467
+ else if (c == '}' && inEnumBody)
2468
+ {
2469
+ cppUngetc (c);
2470
+ setToken (st, TOKEN_COMMA);
2471
+ }
2472
+ if (st->scope == SCOPE_EXTERN)
2473
+ st->scope = SCOPE_GLOBAL;
2474
+ }
2475
+ }
2476
+
2477
+ static void parseIdentifier (statementInfo *const st, const int c)
2478
+ {
2479
+ tokenInfo *const token = activeToken (st);
2480
+
2481
+ readIdentifier (token, c);
2482
+ if (! isType (token, TOKEN_NONE))
2483
+ processToken (token, st);
2484
+ }
2485
+
2486
+ static void parseGeneralToken (statementInfo *const st, const int c)
2487
+ {
2488
+ const tokenInfo *const prev = prevToken (st, 1);
2489
+
2490
+ if (isident1 (c) || (isLanguage (Lang_java) && isHighChar (c)))
2491
+ {
2492
+ parseIdentifier (st, c);
2493
+ if (isType (st->context, TOKEN_NAME) &&
2494
+ isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2495
+ {
2496
+ initToken (st->context);
2497
+ }
2498
+ }
2499
+ else if (c == '.' || c == '-')
2500
+ {
2501
+ if (! st->assignment)
2502
+ st->notVariable = TRUE;
2503
+ if (c == '-')
2504
+ {
2505
+ int c2 = cppGetc ();
2506
+ if (c2 != '>')
2507
+ cppUngetc (c2);
2508
+ }
2509
+ }
2510
+ else if (c == '!' || c == '>')
2511
+ {
2512
+ int c2 = cppGetc ();
2513
+ if (c2 != '=')
2514
+ cppUngetc (c2);
2515
+ }
2516
+ else if (c == '@' && isLanguage (Lang_java))
2517
+ {
2518
+ parseJavaAnnotation (st);
2519
+ }
2520
+ else if (isExternCDecl (st, c))
2521
+ {
2522
+ st->declaration = DECL_NOMANGLE;
2523
+ st->scope = SCOPE_GLOBAL;
2524
+ }
2525
+ }
2526
+
2527
+ /* Reads characters from the pre-processor and assembles tokens, setting
2528
+ * the current statement state.
2529
+ */
2530
+ static void nextToken (statementInfo *const st)
2531
+ {
2532
+ tokenInfo *token;
2533
+ do
2534
+ {
2535
+ int c = skipToNonWhite ();
2536
+ switch (c)
2537
+ {
2538
+ case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2539
+ case '(': analyzeParens (st); break;
2540
+ case '<': processAngleBracket (); break;
2541
+ case '*': st->haveQualifyingName = FALSE; break;
2542
+ case ',': setToken (st, TOKEN_COMMA); break;
2543
+ case ':': processColon (st); break;
2544
+ case ';': setToken (st, TOKEN_SEMICOLON); break;
2545
+ case '=': processInitializer (st); break;
2546
+ case '[': skipToMatch ("[]"); break;
2547
+ case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2548
+ case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2549
+ default: parseGeneralToken (st, c); break;
2550
+ }
2551
+ token = activeToken (st);
2552
+ } while (isType (token, TOKEN_NONE));
2553
+ }
2554
+
2555
+ /*
2556
+ * Scanning support functions
2557
+ */
2558
+
2559
+ static statementInfo *CurrentStatement = NULL;
2560
+
2561
+ static statementInfo *newStatement (statementInfo *const parent)
2562
+ {
2563
+ statementInfo *const st = xMalloc (1, statementInfo);
2564
+ unsigned int i;
2565
+
2566
+ for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2567
+ st->token [i] = newToken ();
2568
+
2569
+ st->context = newToken ();
2570
+ st->blockName = newToken ();
2571
+ st->parentClasses = vStringNew ();
2572
+
2573
+ initStatement (st, parent);
2574
+ CurrentStatement = st;
2575
+
2576
+ return st;
2577
+ }
2578
+
2579
+ static void deleteStatement (void)
2580
+ {
2581
+ statementInfo *const st = CurrentStatement;
2582
+ statementInfo *const parent = st->parent;
2583
+ unsigned int i;
2584
+
2585
+ for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2586
+ {
2587
+ deleteToken (st->token [i]); st->token [i] = NULL;
2588
+ }
2589
+ deleteToken (st->blockName); st->blockName = NULL;
2590
+ deleteToken (st->context); st->context = NULL;
2591
+ vStringDelete (st->parentClasses); st->parentClasses = NULL;
2592
+ eFree (st);
2593
+ CurrentStatement = parent;
2594
+ }
2595
+
2596
+ static void deleteAllStatements (void)
2597
+ {
2598
+ while (CurrentStatement != NULL)
2599
+ deleteStatement ();
2600
+ }
2601
+
2602
+ static boolean isStatementEnd (const statementInfo *const st)
2603
+ {
2604
+ const tokenInfo *const token = activeToken (st);
2605
+ boolean isEnd;
2606
+
2607
+ if (isType (token, TOKEN_SEMICOLON))
2608
+ isEnd = TRUE;
2609
+ else if (isType (token, TOKEN_BRACE_CLOSE))
2610
+ /* Java and C# do not require semicolons to end a block. Neither do C++
2611
+ * namespaces. All other blocks require a semicolon to terminate them.
2612
+ */
2613
+ isEnd = (boolean) (isLanguage (Lang_java) || isLanguage (Lang_csharp) ||
2614
+ ! isContextualStatement (st));
2615
+ else
2616
+ isEnd = FALSE;
2617
+
2618
+ return isEnd;
2619
+ }
2620
+
2621
+ static void checkStatementEnd (statementInfo *const st)
2622
+ {
2623
+ const tokenInfo *const token = activeToken (st);
2624
+
2625
+ if (isType (token, TOKEN_COMMA))
2626
+ reinitStatement (st, TRUE);
2627
+ else if (isStatementEnd (st))
2628
+ {
2629
+ DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2630
+ reinitStatement (st, FALSE);
2631
+ cppEndStatement ();
2632
+ }
2633
+ else
2634
+ {
2635
+ cppBeginStatement ();
2636
+ advanceToken (st);
2637
+ }
2638
+ }
2639
+
2640
+ static void nest (statementInfo *const st, const unsigned int nestLevel)
2641
+ {
2642
+ switch (st->declaration)
2643
+ {
2644
+ case DECL_CLASS:
2645
+ case DECL_ENUM:
2646
+ case DECL_INTERFACE:
2647
+ case DECL_NAMESPACE:
2648
+ case DECL_NOMANGLE:
2649
+ case DECL_STRUCT:
2650
+ case DECL_UNION:
2651
+ createTags (nestLevel, st);
2652
+ break;
2653
+
2654
+ case DECL_FUNCTION:
2655
+ case DECL_TASK:
2656
+ st->inFunction = TRUE;
2657
+ /* fall through */
2658
+ default:
2659
+ if (includeTag (TAG_LOCAL, FALSE))
2660
+ createTags (nestLevel, st);
2661
+ else
2662
+ skipToMatch ("{}");
2663
+ break;
2664
+ }
2665
+ advanceToken (st);
2666
+ setToken (st, TOKEN_BRACE_CLOSE);
2667
+ }
2668
+
2669
+ static void tagCheck (statementInfo *const st)
2670
+ {
2671
+ const tokenInfo *const token = activeToken (st);
2672
+ const tokenInfo *const prev = prevToken (st, 1);
2673
+ const tokenInfo *const prev2 = prevToken (st, 2);
2674
+
2675
+ switch (token->type)
2676
+ {
2677
+ case TOKEN_NAME:
2678
+ if (insideEnumBody (st))
2679
+ qualifyEnumeratorTag (st, token);
2680
+ break;
2681
+ #if 0
2682
+ case TOKEN_PACKAGE:
2683
+ if (st->haveQualifyingName)
2684
+ makeTag (token, st, FALSE, TAG_PACKAGE);
2685
+ break;
2686
+ #endif
2687
+ case TOKEN_BRACE_OPEN:
2688
+ if (isType (prev, TOKEN_ARGS))
2689
+ {
2690
+ if (st->haveQualifyingName)
2691
+ {
2692
+ if (! isLanguage (Lang_vera))
2693
+ st->declaration = DECL_FUNCTION;
2694
+ if (isType (prev2, TOKEN_NAME))
2695
+ copyToken (st->blockName, prev2);
2696
+ qualifyFunctionTag (st, prev2);
2697
+ }
2698
+ }
2699
+ else if (isContextualStatement (st) ||
2700
+ st->declaration == DECL_NAMESPACE ||
2701
+ st->declaration == DECL_PROGRAM)
2702
+ {
2703
+ if (isType (prev, TOKEN_NAME))
2704
+ copyToken (st->blockName, prev);
2705
+ else
2706
+ {
2707
+ /* For an anonymous struct or union we use a unique ID
2708
+ * a number, so that the members can be found.
2709
+ */
2710
+ char buf [20]; /* length of "_anon" + digits + null */
2711
+ sprintf (buf, "__anon%d", ++AnonymousID);
2712
+ vStringCopyS (st->blockName->name, buf);
2713
+ st->blockName->type = TOKEN_NAME;
2714
+ st->blockName->keyword = KEYWORD_NONE;
2715
+ }
2716
+ qualifyBlockTag (st, prev);
2717
+ }
2718
+ else if (isLanguage (Lang_csharp))
2719
+ makeTag (prev, st, FALSE, TAG_PROPERTY);
2720
+ break;
2721
+
2722
+ case TOKEN_SEMICOLON:
2723
+ case TOKEN_COMMA:
2724
+ if (insideEnumBody (st))
2725
+ ;
2726
+ else if (isType (prev, TOKEN_NAME))
2727
+ {
2728
+ if (isContextualKeyword (prev2))
2729
+ makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
2730
+ else
2731
+ qualifyVariableTag (st, prev);
2732
+ }
2733
+ else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
2734
+ {
2735
+ if (st->isPointer)
2736
+ qualifyVariableTag (st, prev2);
2737
+ else
2738
+ qualifyFunctionDeclTag (st, prev2);
2739
+ }
2740
+ if (isLanguage (Lang_java) && token->type == TOKEN_SEMICOLON && insideEnumBody (st))
2741
+ {
2742
+ /* In Java, after an initial enum-like part,
2743
+ * a semicolon introduces a class-like part.
2744
+ * See Bug #1730485 for the full rationale. */
2745
+ st->parent->declaration = DECL_CLASS;
2746
+ }
2747
+ break;
2748
+
2749
+ default: break;
2750
+ }
2751
+ }
2752
+
2753
+ /* Parses the current file and decides whether to write out and tags that
2754
+ * are discovered.
2755
+ */
2756
+ static void createTags (const unsigned int nestLevel,
2757
+ statementInfo *const parent)
2758
+ {
2759
+ statementInfo *const st = newStatement (parent);
2760
+
2761
+ DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
2762
+ while (TRUE)
2763
+ {
2764
+ tokenInfo *token;
2765
+
2766
+ nextToken (st);
2767
+ token = activeToken (st);
2768
+ if (isType (token, TOKEN_BRACE_CLOSE))
2769
+ {
2770
+ if (nestLevel > 0)
2771
+ break;
2772
+ else
2773
+ {
2774
+ verbose ("%s: unexpected closing brace at line %lu\n",
2775
+ getInputFileName (), getInputLineNumber ());
2776
+ longjmp (Exception, (int) ExceptionBraceFormattingError);
2777
+ }
2778
+ }
2779
+ else if (isType (token, TOKEN_DOUBLE_COLON))
2780
+ {
2781
+ addContext (st, prevToken (st, 1));
2782
+ advanceToken (st);
2783
+ }
2784
+ else
2785
+ {
2786
+ tagCheck (st);
2787
+ if (isType (token, TOKEN_BRACE_OPEN))
2788
+ nest (st, nestLevel + 1);
2789
+ checkStatementEnd (st);
2790
+ }
2791
+ }
2792
+ deleteStatement ();
2793
+ DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
2794
+ }
2795
+
2796
+ static boolean findCTags (const unsigned int passCount)
2797
+ {
2798
+ exception_t exception;
2799
+ boolean retry;
2800
+
2801
+ Assert (passCount < 3);
2802
+ cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
2803
+ Signature = vStringNew ();
2804
+
2805
+ exception = (exception_t) setjmp (Exception);
2806
+ retry = FALSE;
2807
+ if (exception == ExceptionNone)
2808
+ createTags (0, NULL);
2809
+ else
2810
+ {
2811
+ deleteAllStatements ();
2812
+ if (exception == ExceptionBraceFormattingError && passCount == 1)
2813
+ {
2814
+ retry = TRUE;
2815
+ verbose ("%s: retrying file with fallback brace matching algorithm\n",
2816
+ getInputFileName ());
2817
+ }
2818
+ }
2819
+ vStringDelete (Signature);
2820
+ cppTerminate ();
2821
+ return retry;
2822
+ }
2823
+
2824
+ static void buildKeywordHash (const langType language, unsigned int idx)
2825
+ {
2826
+ const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
2827
+ size_t i;
2828
+ for (i = 0 ; i < count ; ++i)
2829
+ {
2830
+ const keywordDesc* const p = &KeywordTable [i];
2831
+ if (p->isValid [idx])
2832
+ addKeyword (p->name, language, (int) p->id);
2833
+ }
2834
+ }
2835
+
2836
+ static void initializeCParser (const langType language)
2837
+ {
2838
+ Lang_c = language;
2839
+ buildKeywordHash (language, 0);
2840
+ }
2841
+
2842
+ static void initializeCppParser (const langType language)
2843
+ {
2844
+ Lang_cpp = language;
2845
+ buildKeywordHash (language, 1);
2846
+ }
2847
+
2848
+ static void initializeCsharpParser (const langType language)
2849
+ {
2850
+ Lang_csharp = language;
2851
+ buildKeywordHash (language, 2);
2852
+ }
2853
+
2854
+ static void initializeJavaParser (const langType language)
2855
+ {
2856
+ Lang_java = language;
2857
+ buildKeywordHash (language, 3);
2858
+ }
2859
+
2860
+ static void initializeVeraParser (const langType language)
2861
+ {
2862
+ Lang_vera = language;
2863
+ buildKeywordHash (language, 4);
2864
+ }
2865
+
2866
+ extern parserDefinition* CParser (void)
2867
+ {
2868
+ static const char *const extensions [] = { "c", NULL };
2869
+ parserDefinition* def = parserNew ("C");
2870
+ def->kinds = CKinds;
2871
+ def->kindCount = KIND_COUNT (CKinds);
2872
+ def->extensions = extensions;
2873
+ def->parser2 = findCTags;
2874
+ def->initialize = initializeCParser;
2875
+ return def;
2876
+ }
2877
+
2878
+ extern parserDefinition* CppParser (void)
2879
+ {
2880
+ static const char *const extensions [] = {
2881
+ "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
2882
+ #ifndef CASE_INSENSITIVE_FILENAMES
2883
+ "C", "H",
2884
+ #endif
2885
+ NULL
2886
+ };
2887
+ parserDefinition* def = parserNew ("C++");
2888
+ def->kinds = CKinds;
2889
+ def->kindCount = KIND_COUNT (CKinds);
2890
+ def->extensions = extensions;
2891
+ def->parser2 = findCTags;
2892
+ def->initialize = initializeCppParser;
2893
+ return def;
2894
+ }
2895
+
2896
+ extern parserDefinition* CsharpParser (void)
2897
+ {
2898
+ static const char *const extensions [] = { "cs", NULL };
2899
+ parserDefinition* def = parserNew ("C#");
2900
+ def->kinds = CsharpKinds;
2901
+ def->kindCount = KIND_COUNT (CsharpKinds);
2902
+ def->extensions = extensions;
2903
+ def->parser2 = findCTags;
2904
+ def->initialize = initializeCsharpParser;
2905
+ return def;
2906
+ }
2907
+
2908
+ extern parserDefinition* JavaParser (void)
2909
+ {
2910
+ static const char *const extensions [] = { "java", NULL };
2911
+ parserDefinition* def = parserNew ("Java");
2912
+ def->kinds = JavaKinds;
2913
+ def->kindCount = KIND_COUNT (JavaKinds);
2914
+ def->extensions = extensions;
2915
+ def->parser2 = findCTags;
2916
+ def->initialize = initializeJavaParser;
2917
+ return def;
2918
+ }
2919
+
2920
+ extern parserDefinition* VeraParser (void)
2921
+ {
2922
+ static const char *const extensions [] = { "vr", "vri", "vrh", NULL };
2923
+ parserDefinition* def = parserNew ("Vera");
2924
+ def->kinds = VeraKinds;
2925
+ def->kindCount = KIND_COUNT (VeraKinds);
2926
+ def->extensions = extensions;
2927
+ def->parser2 = findCTags;
2928
+ def->initialize = initializeVeraParser;
2929
+ return def;
2930
+ }
2931
+
2932
+ /* vi:set tabstop=4 shiftwidth=4 noexpandtab: */