ctags.rb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,1352 @@
1
+ /*
2
+ * $Id: eiffel.c 706 2009-06-28 23:09:30Z dhiebert $
3
+ *
4
+ * Copyright (c) 1998-2002, 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 generating tags for Eiffel language
10
+ * files.
11
+ */
12
+
13
+ /*
14
+ * INCLUDE FILES
15
+ */
16
+ #include "general.h" /* must always come first */
17
+
18
+ #ifdef TYPE_REFERENCE_TOOL
19
+ #include <stdio.h>
20
+ #endif
21
+ #include <string.h>
22
+ #include <limits.h>
23
+ #include <ctype.h> /* to define tolower () */
24
+ #include <setjmp.h>
25
+
26
+ #include "debug.h"
27
+ #include "keyword.h"
28
+ #include "routines.h"
29
+ #include "vstring.h"
30
+ #ifndef TYPE_REFERENCE_TOOL
31
+ #include "entry.h"
32
+ #include "options.h"
33
+ #include "parse.h"
34
+ #include "read.h"
35
+ #endif
36
+
37
+ /*
38
+ * MACROS
39
+ */
40
+ #define isident(c) (isalnum(c) || (c) == '_')
41
+ #define isFreeOperatorChar(c) ((c) == '@' || (c) == '#' || \
42
+ (c) == '|' || (c) == '&')
43
+ #define isType(token,t) (boolean) ((token)->type == (t))
44
+ #define isKeyword(token,k) (boolean) ((token)->keyword == (k))
45
+
46
+ /*
47
+ * DATA DECLARATIONS
48
+ */
49
+
50
+ typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
51
+
52
+ /* Used to specify type of keyword.
53
+ */
54
+ typedef enum eKeywordId {
55
+ KEYWORD_NONE = -1,
56
+ KEYWORD_alias, KEYWORD_all, KEYWORD_and, KEYWORD_as, KEYWORD_assign,
57
+ KEYWORD_check, KEYWORD_class, KEYWORD_convert, KEYWORD_create,
58
+ KEYWORD_creation, KEYWORD_Current,
59
+ KEYWORD_debug, KEYWORD_deferred, KEYWORD_do, KEYWORD_else,
60
+ KEYWORD_elseif, KEYWORD_end, KEYWORD_ensure, KEYWORD_expanded,
61
+ KEYWORD_export, KEYWORD_external, KEYWORD_false, KEYWORD_feature,
62
+ KEYWORD_from, KEYWORD_frozen, KEYWORD_if, KEYWORD_implies,
63
+ KEYWORD_indexing, KEYWORD_infix, KEYWORD_inherit, KEYWORD_inspect,
64
+ KEYWORD_invariant, KEYWORD_is, KEYWORD_like, KEYWORD_local,
65
+ KEYWORD_loop, KEYWORD_not, KEYWORD_obsolete, KEYWORD_old, KEYWORD_once,
66
+ KEYWORD_or, KEYWORD_prefix, KEYWORD_redefine, KEYWORD_rename,
67
+ KEYWORD_require, KEYWORD_rescue, KEYWORD_Result, KEYWORD_retry,
68
+ KEYWORD_select, KEYWORD_separate, KEYWORD_strip, KEYWORD_then,
69
+ KEYWORD_true, KEYWORD_undefine, KEYWORD_unique, KEYWORD_until,
70
+ KEYWORD_variant, KEYWORD_when, KEYWORD_xor
71
+ } keywordId;
72
+
73
+ /* Used to determine whether keyword is valid for the token language and
74
+ * what its ID is.
75
+ */
76
+ typedef struct sKeywordDesc {
77
+ const char *name;
78
+ keywordId id;
79
+ } keywordDesc;
80
+
81
+ typedef enum eTokenType {
82
+ TOKEN_UNDEFINED,
83
+ TOKEN_BANG,
84
+ TOKEN_CHARACTER,
85
+ TOKEN_CLOSE_BRACE,
86
+ TOKEN_CLOSE_BRACKET,
87
+ TOKEN_CLOSE_PAREN,
88
+ TOKEN_COLON,
89
+ TOKEN_COMMA,
90
+ TOKEN_CONSTRAINT,
91
+ TOKEN_DOT,
92
+ TOKEN_DOLLAR,
93
+ TOKEN_IDENTIFIER,
94
+ TOKEN_KEYWORD,
95
+ TOKEN_NUMERIC,
96
+ TOKEN_OPEN_BRACE,
97
+ TOKEN_OPEN_BRACKET,
98
+ TOKEN_OPEN_PAREN,
99
+ TOKEN_OPERATOR,
100
+ TOKEN_OTHER,
101
+ TOKEN_QUESTION,
102
+ TOKEN_SEMICOLON,
103
+ TOKEN_SEPARATOR,
104
+ TOKEN_STRING,
105
+ TOKEN_TILDE
106
+ } tokenType;
107
+
108
+ typedef struct sTokenInfo {
109
+ tokenType type;
110
+ keywordId keyword;
111
+ boolean isExported;
112
+ vString* string;
113
+ vString* className;
114
+ vString* featureName;
115
+ } tokenInfo;
116
+
117
+ /*
118
+ * DATA DEFINITIONS
119
+ */
120
+
121
+ static langType Lang_eiffel;
122
+
123
+ #ifdef TYPE_REFERENCE_TOOL
124
+
125
+ static const char *FileName;
126
+ static FILE *File;
127
+ static int PrintClass;
128
+ static int PrintReferences;
129
+ static int SelfReferences;
130
+ static int Debug;
131
+ static stringList *GenericNames;
132
+ static stringList *ReferencedTypes;
133
+
134
+ #else
135
+
136
+ typedef enum {
137
+ EKIND_CLASS, EKIND_FEATURE, EKIND_LOCAL, EKIND_QUALIFIED_TAGS
138
+ } eiffelKind;
139
+
140
+ static kindOption EiffelKinds [] = {
141
+ { TRUE, 'c', "class", "classes"},
142
+ { TRUE, 'f', "feature", "features"},
143
+ { FALSE, 'l', "local", "local entities"}
144
+ };
145
+
146
+ #endif
147
+
148
+ static jmp_buf Exception;
149
+
150
+ static const keywordDesc EiffelKeywordTable [] = {
151
+ /* keyword keyword ID */
152
+ { "alias", KEYWORD_alias },
153
+ { "all", KEYWORD_all },
154
+ { "and", KEYWORD_and },
155
+ { "as", KEYWORD_as },
156
+ { "assign", KEYWORD_assign },
157
+ { "check", KEYWORD_check },
158
+ { "class", KEYWORD_class },
159
+ { "convert", KEYWORD_convert },
160
+ { "create", KEYWORD_create },
161
+ { "creation", KEYWORD_creation },
162
+ { "current", KEYWORD_Current },
163
+ { "debug", KEYWORD_debug },
164
+ { "deferred", KEYWORD_deferred },
165
+ { "do", KEYWORD_do },
166
+ { "else", KEYWORD_else },
167
+ { "elseif", KEYWORD_elseif },
168
+ { "end", KEYWORD_end },
169
+ { "ensure", KEYWORD_ensure },
170
+ { "expanded", KEYWORD_expanded },
171
+ { "export", KEYWORD_export },
172
+ { "external", KEYWORD_external },
173
+ { "false", KEYWORD_false },
174
+ { "feature", KEYWORD_feature },
175
+ { "from", KEYWORD_from },
176
+ { "frozen", KEYWORD_frozen },
177
+ { "if", KEYWORD_if },
178
+ { "implies", KEYWORD_implies },
179
+ { "indexing", KEYWORD_indexing },
180
+ { "infix", KEYWORD_infix },
181
+ { "inherit", KEYWORD_inherit },
182
+ { "inspect", KEYWORD_inspect },
183
+ { "invariant", KEYWORD_invariant },
184
+ { "is", KEYWORD_is },
185
+ { "like", KEYWORD_like },
186
+ { "local", KEYWORD_local },
187
+ { "loop", KEYWORD_loop },
188
+ { "not", KEYWORD_not },
189
+ { "obsolete", KEYWORD_obsolete },
190
+ { "old", KEYWORD_old },
191
+ { "once", KEYWORD_once },
192
+ { "or", KEYWORD_or },
193
+ { "prefix", KEYWORD_prefix },
194
+ { "redefine", KEYWORD_redefine },
195
+ { "rename", KEYWORD_rename },
196
+ { "require", KEYWORD_require },
197
+ { "rescue", KEYWORD_rescue },
198
+ { "result", KEYWORD_Result },
199
+ { "retry", KEYWORD_retry },
200
+ { "select", KEYWORD_select },
201
+ { "separate", KEYWORD_separate },
202
+ { "strip", KEYWORD_strip },
203
+ { "then", KEYWORD_then },
204
+ { "true", KEYWORD_true },
205
+ { "undefine", KEYWORD_undefine },
206
+ { "unique", KEYWORD_unique },
207
+ { "until", KEYWORD_until },
208
+ { "variant", KEYWORD_variant },
209
+ { "when", KEYWORD_when },
210
+ { "xor", KEYWORD_xor }
211
+ };
212
+
213
+ /*
214
+ * FUNCTION DEFINITIONS
215
+ */
216
+
217
+ static void buildEiffelKeywordHash (void)
218
+ {
219
+ const size_t count = sizeof (EiffelKeywordTable) /
220
+ sizeof (EiffelKeywordTable [0]);
221
+ size_t i;
222
+ for (i = 0 ; i < count ; ++i)
223
+ {
224
+ const keywordDesc* const p = &EiffelKeywordTable [i];
225
+ addKeyword (p->name, Lang_eiffel, (int) p->id);
226
+ }
227
+ }
228
+
229
+ #ifdef TYPE_REFERENCE_TOOL
230
+
231
+ static void addGenericName (tokenInfo *const token)
232
+ {
233
+ vStringUpper (token->string);
234
+ if (vStringLength (token->string) > 0)
235
+ stringListAdd (GenericNames, vStringNewCopy (token->string));
236
+ }
237
+
238
+ static boolean isGeneric (tokenInfo *const token)
239
+ {
240
+ return (boolean) stringListHas (GenericNames, vStringValue (token->string));
241
+ }
242
+
243
+ static void reportType (tokenInfo *const token)
244
+ {
245
+ vStringUpper (token->string);
246
+ if (vStringLength (token->string) > 0 && ! isGeneric (token) &&
247
+ (SelfReferences || strcmp (vStringValue (
248
+ token->string), vStringValue (token->className)) != 0) &&
249
+ ! stringListHas (ReferencedTypes, vStringValue (token->string)))
250
+ {
251
+ printf ("%s\n", vStringValue (token->string));
252
+ stringListAdd (ReferencedTypes, vStringNewCopy (token->string));
253
+ }
254
+ }
255
+
256
+ static int fileGetc (void)
257
+ {
258
+ int c = getc (File);
259
+ if (c == '\r')
260
+ {
261
+ c = getc (File);
262
+ if (c != '\n')
263
+ {
264
+ ungetc (c, File);
265
+ c = '\n';
266
+ }
267
+ }
268
+ if (Debug > 0 && c != EOF)
269
+ putc (c, errout);
270
+ return c;
271
+ }
272
+
273
+ static int fileUngetc (c)
274
+ {
275
+ return ungetc (c, File);
276
+ }
277
+
278
+ extern char *readLine (vString *const vLine, FILE *const fp)
279
+ {
280
+ return NULL;
281
+ }
282
+
283
+ #else
284
+
285
+ /*
286
+ * Tag generation functions
287
+ */
288
+
289
+ static void makeEiffelClassTag (tokenInfo *const token)
290
+ {
291
+ if (EiffelKinds [EKIND_CLASS].enabled)
292
+ {
293
+ const char *const name = vStringValue (token->string);
294
+ tagEntryInfo e;
295
+
296
+ initTagEntry (&e, name);
297
+
298
+ e.kindName = EiffelKinds [EKIND_CLASS].name;
299
+ e.kind = EiffelKinds [EKIND_CLASS].letter;
300
+
301
+ makeTagEntry (&e);
302
+ }
303
+ vStringCopy (token->className, token->string);
304
+ }
305
+
306
+ static void makeEiffelFeatureTag (tokenInfo *const token)
307
+ {
308
+ if (EiffelKinds [EKIND_FEATURE].enabled &&
309
+ (token->isExported || Option.include.fileScope))
310
+ {
311
+ const char *const name = vStringValue (token->string);
312
+ tagEntryInfo e;
313
+
314
+ initTagEntry (&e, name);
315
+
316
+ e.isFileScope = (boolean) (! token->isExported);
317
+ e.kindName = EiffelKinds [EKIND_FEATURE].name;
318
+ e.kind = EiffelKinds [EKIND_FEATURE].letter;
319
+ e.extensionFields.scope [0] = EiffelKinds [EKIND_CLASS].name;
320
+ e.extensionFields.scope [1] = vStringValue (token->className);
321
+
322
+ makeTagEntry (&e);
323
+
324
+ if (Option.include.qualifiedTags)
325
+ {
326
+ vString* qualified = vStringNewInit (vStringValue (token->className));
327
+ vStringPut (qualified, '.');
328
+ vStringCat (qualified, token->string);
329
+ e.name = vStringValue (qualified);
330
+ makeTagEntry (&e);
331
+ vStringDelete (qualified);
332
+ }
333
+ }
334
+ vStringCopy (token->featureName, token->string);
335
+ }
336
+
337
+ static void makeEiffelLocalTag (tokenInfo *const token)
338
+ {
339
+ if (EiffelKinds [EKIND_LOCAL].enabled && Option.include.fileScope)
340
+ {
341
+ const char *const name = vStringValue (token->string);
342
+ vString* scope = vStringNew ();
343
+ tagEntryInfo e;
344
+
345
+ initTagEntry (&e, name);
346
+
347
+ e.isFileScope = TRUE;
348
+ e.kindName = EiffelKinds [EKIND_LOCAL].name;
349
+ e.kind = EiffelKinds [EKIND_LOCAL].letter;
350
+
351
+ vStringCopy (scope, token->className);
352
+ vStringPut (scope, '.');
353
+ vStringCat (scope, token->featureName);
354
+
355
+ e.extensionFields.scope [0] = EiffelKinds [EKIND_FEATURE].name;
356
+ e.extensionFields.scope [1] = vStringValue (scope);
357
+
358
+ makeTagEntry (&e);
359
+ vStringDelete (scope);
360
+ }
361
+ }
362
+
363
+ #endif
364
+
365
+ /*
366
+ * Parsing functions
367
+ */
368
+
369
+ static int skipToCharacter (const int c)
370
+ {
371
+ int d;
372
+
373
+ do
374
+ {
375
+ d = fileGetc ();
376
+ } while (d != EOF && d != c);
377
+
378
+ return d;
379
+ }
380
+
381
+ /* If a numeric is passed in 'c', this is used as the first digit of the
382
+ * numeric being parsed.
383
+ */
384
+ static vString *parseInteger (int c)
385
+ {
386
+ vString *string = vStringNew ();
387
+
388
+ if (c == '\0')
389
+ c = fileGetc ();
390
+ if (c == '-')
391
+ {
392
+ vStringPut (string, c);
393
+ c = fileGetc ();
394
+ }
395
+ else if (! isdigit (c))
396
+ c = fileGetc ();
397
+ while (c != EOF && (isdigit (c) || c == '_'))
398
+ {
399
+ vStringPut (string, c);
400
+ c = fileGetc ();
401
+ }
402
+ vStringTerminate (string);
403
+ fileUngetc (c);
404
+
405
+ return string;
406
+ }
407
+
408
+ static vString *parseNumeric (int c)
409
+ {
410
+ vString *string = vStringNew ();
411
+ vString *integer = parseInteger (c);
412
+ vStringCopy (string, integer);
413
+ vStringDelete (integer);
414
+
415
+ c = fileGetc ();
416
+ if (c == '.')
417
+ {
418
+ integer = parseInteger ('\0');
419
+ vStringPut (string, c);
420
+ vStringCat (string, integer);
421
+ vStringDelete (integer);
422
+ c = fileGetc ();
423
+ }
424
+ if (tolower (c) == 'e')
425
+ {
426
+ integer = parseInteger ('\0');
427
+ vStringPut (string, c);
428
+ vStringCat (string, integer);
429
+ vStringDelete (integer);
430
+ }
431
+ else if (!isspace (c))
432
+ fileUngetc (c);
433
+
434
+ vStringTerminate (string);
435
+
436
+ return string;
437
+ }
438
+
439
+ static int parseEscapedCharacter (void)
440
+ {
441
+ int d = '\0';
442
+ int c = fileGetc ();
443
+
444
+ switch (c)
445
+ {
446
+ case 'A': d = '@'; break;
447
+ case 'B': d = '\b'; break;
448
+ case 'C': d = '^'; break;
449
+ case 'D': d = '$'; break;
450
+ case 'F': d = '\f'; break;
451
+ case 'H': d = '\\'; break;
452
+ case 'L': d = '~'; break;
453
+ case 'N': d = '\n'; break;
454
+ #ifdef QDOS
455
+ case 'Q': d = 0x9F; break;
456
+ #else
457
+ case 'Q': d = '`'; break;
458
+ #endif
459
+ case 'R': d = '\r'; break;
460
+ case 'S': d = '#'; break;
461
+ case 'T': d = '\t'; break;
462
+ case 'U': d = '\0'; break;
463
+ case 'V': d = '|'; break;
464
+ case '%': d = '%'; break;
465
+ case '\'': d = '\''; break;
466
+ case '"': d = '"'; break;
467
+ case '(': d = '['; break;
468
+ case ')': d = ']'; break;
469
+ case '<': d = '{'; break;
470
+ case '>': d = '}'; break;
471
+
472
+ case '\n': skipToCharacter ('%'); break;
473
+
474
+ case '/':
475
+ {
476
+ vString *string = parseInteger ('\0');
477
+ const char *value = vStringValue (string);
478
+ const unsigned long ascii = atol (value);
479
+ vStringDelete (string);
480
+
481
+ c = fileGetc ();
482
+ if (c == '/' && ascii < 256)
483
+ d = ascii;
484
+ break;
485
+ }
486
+
487
+ default: break;
488
+ }
489
+ return d;
490
+ }
491
+
492
+ static int parseCharacter (void)
493
+ {
494
+ int c = fileGetc ();
495
+ int result = c;
496
+
497
+ if (c == '%')
498
+ result = parseEscapedCharacter ();
499
+
500
+ c = fileGetc ();
501
+ if (c != '\'')
502
+ skipToCharacter ('\n');
503
+
504
+ return result;
505
+ }
506
+
507
+ static void parseString (vString *const string)
508
+ {
509
+ boolean verbatim = FALSE;
510
+ boolean align = FALSE;
511
+ boolean end = FALSE;
512
+ vString *verbatimCloser = vStringNew ();
513
+ vString *lastLine = vStringNew ();
514
+ int prev = '\0';
515
+ int c;
516
+
517
+ while (! end)
518
+ {
519
+ c = fileGetc ();
520
+ if (c == EOF)
521
+ end = TRUE;
522
+ else if (c == '"')
523
+ {
524
+ if (! verbatim)
525
+ end = TRUE;
526
+ else
527
+ end = (boolean) (strcmp (vStringValue (lastLine),
528
+ vStringValue (verbatimCloser)) == 0);
529
+ }
530
+ else if (c == '\n')
531
+ {
532
+ if (verbatim)
533
+ vStringClear (lastLine);
534
+ if (prev == '[' /* || prev == '{' */)
535
+ {
536
+ verbatim = TRUE;
537
+ vStringClear (verbatimCloser);
538
+ vStringClear (lastLine);
539
+ if (prev == '{')
540
+ vStringPut (verbatimCloser, '}');
541
+ else
542
+ {
543
+ vStringPut (verbatimCloser, ']');
544
+ align = TRUE;
545
+ }
546
+ vStringNCat (verbatimCloser, string, vStringLength (string) - 1);
547
+ vStringClear (string);
548
+ }
549
+ if (verbatim && align)
550
+ {
551
+ do
552
+ c = fileGetc ();
553
+ while (isspace (c));
554
+ }
555
+ }
556
+ else if (c == '%')
557
+ c = parseEscapedCharacter ();
558
+ if (! end)
559
+ {
560
+ vStringPut (string, c);
561
+ if (verbatim)
562
+ {
563
+ vStringPut (lastLine, c);
564
+ vStringTerminate (lastLine);
565
+ }
566
+ prev = c;
567
+ }
568
+ }
569
+ vStringTerminate (string);
570
+ vStringDelete (lastLine);
571
+ vStringDelete (verbatimCloser);
572
+ }
573
+
574
+ /* Read a C identifier beginning with "firstChar" and places it into "name".
575
+ */
576
+ static void parseIdentifier (vString *const string, const int firstChar)
577
+ {
578
+ int c = firstChar;
579
+
580
+ do
581
+ {
582
+ vStringPut (string, c);
583
+ c = fileGetc ();
584
+ } while (isident (c));
585
+
586
+ vStringTerminate (string);
587
+ if (!isspace (c))
588
+ fileUngetc (c); /* unget non-identifier character */
589
+ }
590
+
591
+ static void parseFreeOperator (vString *const string, const int firstChar)
592
+ {
593
+ int c = firstChar;
594
+
595
+ do
596
+ {
597
+ vStringPut (string, c);
598
+ c = fileGetc ();
599
+ } while (c > ' ');
600
+
601
+ vStringTerminate (string);
602
+ if (!isspace (c))
603
+ fileUngetc (c); /* unget non-identifier character */
604
+ }
605
+
606
+ static void copyToken (tokenInfo* dst, const tokenInfo *src)
607
+ {
608
+ dst->type = src->type;
609
+ dst->keyword = src->keyword;
610
+ dst->isExported = src->isExported;
611
+
612
+ vStringCopy (dst->string, src->string);
613
+ vStringCopy (dst->className, src->className);
614
+ vStringCopy (dst->featureName, src->featureName);
615
+ }
616
+
617
+ static tokenInfo *newToken (void)
618
+ {
619
+ tokenInfo *const token = xMalloc (1, tokenInfo);
620
+
621
+ token->type = TOKEN_UNDEFINED;
622
+ token->keyword = KEYWORD_NONE;
623
+ token->isExported = TRUE;
624
+
625
+ token->string = vStringNew ();
626
+ token->className = vStringNew ();
627
+ token->featureName = vStringNew ();
628
+
629
+ return token;
630
+ }
631
+
632
+ static void deleteToken (tokenInfo *const token)
633
+ {
634
+ vStringDelete (token->string);
635
+ vStringDelete (token->className);
636
+ vStringDelete (token->featureName);
637
+
638
+ eFree (token);
639
+ }
640
+
641
+ static void readToken (tokenInfo *const token)
642
+ {
643
+ int c;
644
+
645
+ token->type = TOKEN_UNDEFINED;
646
+ token->keyword = KEYWORD_NONE;
647
+ vStringClear (token->string);
648
+
649
+ getNextChar:
650
+
651
+ do
652
+ c = fileGetc ();
653
+ while (c == '\t' || c == ' ' || c == '\n');
654
+
655
+ switch (c)
656
+ {
657
+ case EOF: longjmp (Exception, (int)ExceptionEOF); break;
658
+ case ';': token->type = TOKEN_SEMICOLON; break;
659
+ case '!': token->type = TOKEN_BANG; break;
660
+ case '}': token->type = TOKEN_CLOSE_BRACE; break;
661
+ case ']': token->type = TOKEN_CLOSE_BRACKET; break;
662
+ case ')': token->type = TOKEN_CLOSE_PAREN; break;
663
+ case ',': token->type = TOKEN_COMMA; break;
664
+ case '$': token->type = TOKEN_DOLLAR; break;
665
+ case '.': token->type = TOKEN_DOT; break;
666
+ case '{': token->type = TOKEN_OPEN_BRACE; break;
667
+ case '[': token->type = TOKEN_OPEN_BRACKET; break;
668
+ case '(': token->type = TOKEN_OPEN_PAREN; break;
669
+ case '~': token->type = TOKEN_TILDE; break;
670
+
671
+
672
+ case '+':
673
+ case '*':
674
+ case '^':
675
+ case '=': token->type = TOKEN_OPERATOR; break;
676
+
677
+ case '-':
678
+ c = fileGetc ();
679
+ if (c == '>')
680
+ token->type = TOKEN_CONSTRAINT;
681
+ else if (c == '-') /* is this the start of a comment? */
682
+ {
683
+ skipToCharacter ('\n');
684
+ goto getNextChar;
685
+ }
686
+ else
687
+ {
688
+ if (!isspace (c))
689
+ fileUngetc (c);
690
+ token->type = TOKEN_OPERATOR;
691
+ }
692
+ break;
693
+
694
+ case '?':
695
+ case ':':
696
+ {
697
+ int c2 = fileGetc ();
698
+ if (c2 == '=')
699
+ token->type = TOKEN_OPERATOR;
700
+ else
701
+ {
702
+ if (!isspace (c2))
703
+ fileUngetc (c2);
704
+ if (c == ':')
705
+ token->type = TOKEN_COLON;
706
+ else
707
+ token->type = TOKEN_QUESTION;
708
+ }
709
+ break;
710
+ }
711
+
712
+ case '<':
713
+ c = fileGetc ();
714
+ if (c != '=' && c != '>' && !isspace (c))
715
+ fileUngetc (c);
716
+ token->type = TOKEN_OPERATOR;
717
+ break;
718
+
719
+ case '>':
720
+ c = fileGetc ();
721
+ if (c != '=' && c != '>' && !isspace (c))
722
+ fileUngetc (c);
723
+ token->type = TOKEN_OPERATOR;
724
+ break;
725
+
726
+ case '/':
727
+ c = fileGetc ();
728
+ if (c != '/' && c != '=' && !isspace (c))
729
+ fileUngetc (c);
730
+ token->type = TOKEN_OPERATOR;
731
+ break;
732
+
733
+ case '\\':
734
+ c = fileGetc ();
735
+ if (c != '\\' && !isspace (c))
736
+ fileUngetc (c);
737
+ token->type = TOKEN_OPERATOR;
738
+ break;
739
+
740
+ case '"':
741
+ token->type = TOKEN_STRING;
742
+ parseString (token->string);
743
+ break;
744
+
745
+ case '\'':
746
+ token->type = TOKEN_CHARACTER;
747
+ parseCharacter ();
748
+ break;
749
+
750
+ default:
751
+ if (isalpha (c))
752
+ {
753
+ parseIdentifier (token->string, c);
754
+ token->keyword = analyzeToken (token->string, Lang_eiffel);
755
+ if (isKeyword (token, KEYWORD_NONE))
756
+ token->type = TOKEN_IDENTIFIER;
757
+ else
758
+ token->type = TOKEN_KEYWORD;
759
+ }
760
+ else if (isdigit (c))
761
+ {
762
+ vString* numeric = parseNumeric (c);
763
+ vStringCat (token->string, numeric);
764
+ vStringDelete (numeric);
765
+ token->type = TOKEN_NUMERIC;
766
+ }
767
+ else if (isFreeOperatorChar (c))
768
+ {
769
+ parseFreeOperator (token->string, c);
770
+ token->type = TOKEN_OPERATOR;
771
+ }
772
+ else
773
+ {
774
+ token->type = TOKEN_UNDEFINED;
775
+ Assert (! isType (token, TOKEN_UNDEFINED));
776
+ }
777
+ break;
778
+ }
779
+ }
780
+
781
+ /*
782
+ * Scanning functions
783
+ */
784
+
785
+ static boolean isIdentifierMatch (
786
+ const tokenInfo *const token, const char *const name)
787
+ {
788
+ return (boolean) (isType (token, TOKEN_IDENTIFIER) &&
789
+ strcasecmp (vStringValue (token->string), name) == 0);
790
+ }
791
+
792
+ static void findToken (tokenInfo *const token, const tokenType type)
793
+ {
794
+ while (! isType (token, type))
795
+ readToken (token);
796
+ }
797
+
798
+ static void findKeyword (tokenInfo *const token, const keywordId keyword)
799
+ {
800
+ while (! isKeyword (token, keyword))
801
+ readToken (token);
802
+ }
803
+
804
+ static boolean parseType (tokenInfo *const token);
805
+
806
+ static void parseGeneric (tokenInfo *const token, boolean declaration __unused__)
807
+ {
808
+ unsigned int depth = 0;
809
+ #ifdef TYPE_REFERENCE_TOOL
810
+ boolean constraint = FALSE;
811
+ #endif
812
+ Assert (isType (token, TOKEN_OPEN_BRACKET));
813
+ do
814
+ {
815
+ if (isType (token, TOKEN_OPEN_BRACKET))
816
+ {
817
+ ++depth;
818
+ readToken (token);
819
+ }
820
+ else if (isType (token, TOKEN_CLOSE_BRACKET))
821
+ {
822
+ --depth;
823
+ readToken (token);
824
+ }
825
+ #ifdef TYPE_REFERENCE_TOOL
826
+ else if (declaration)
827
+ {
828
+ boolean advanced = FALSE;
829
+ if (depth == 1)
830
+ {
831
+ if (isType (token, TOKEN_CONSTRAINT))
832
+ constraint = TRUE;
833
+ else if (isKeyword (token, KEYWORD_create))
834
+ findKeyword (token, KEYWORD_end);
835
+ else if (isType (token, TOKEN_IDENTIFIER))
836
+ {
837
+ if (constraint)
838
+ advanced = parseType (token);
839
+ else
840
+ addGenericName (token);
841
+ constraint = FALSE;
842
+ }
843
+ }
844
+ else if (isType (token, TOKEN_IDENTIFIER))
845
+ advanced = parseType (token);
846
+ if (! advanced)
847
+ readToken (token);
848
+ }
849
+ #endif
850
+ else
851
+ parseType (token);
852
+ } while (depth > 0);
853
+ }
854
+
855
+ static boolean parseType (tokenInfo *const token)
856
+ {
857
+ tokenInfo* const id = newToken ();
858
+ copyToken (id, token);
859
+ readToken (token);
860
+ if (isType (token, TOKEN_COLON)) /* check for "{entity: TYPE}" */
861
+ {
862
+ readToken (id);
863
+ readToken (token);
864
+ }
865
+ if (isKeyword (id, KEYWORD_like))
866
+ {
867
+ if (isType (token, TOKEN_IDENTIFIER) ||
868
+ isKeyword (token, KEYWORD_Current))
869
+ readToken (token);
870
+ }
871
+ else
872
+ {
873
+ if (isKeyword (id, KEYWORD_expanded))
874
+ {
875
+ copyToken (id, token);
876
+ readToken (token);
877
+ }
878
+ if (isType (id, TOKEN_IDENTIFIER))
879
+ {
880
+ #ifdef TYPE_REFERENCE_TOOL
881
+ reportType (id);
882
+ #endif
883
+ if (isType (token, TOKEN_OPEN_BRACKET))
884
+ parseGeneric (token, FALSE);
885
+ else if ((strcmp ("BIT", vStringValue (id->string)) == 0))
886
+ readToken (token); /* read token after number of bits */
887
+ }
888
+ }
889
+ deleteToken (id);
890
+ return TRUE;
891
+ }
892
+
893
+ static void parseEntityType (tokenInfo *const token)
894
+ {
895
+ Assert (isType (token, TOKEN_COLON));
896
+ readToken (token);
897
+
898
+ if (isType (token, TOKEN_BANG) || isType (token, TOKEN_QUESTION))
899
+ readToken (token); /* skip over '!' or '?' */
900
+ parseType (token);
901
+ }
902
+
903
+ static void parseLocal (tokenInfo *const token)
904
+ {
905
+ Assert (isKeyword (token, KEYWORD_local));
906
+ readToken (token);
907
+
908
+ /* Check keyword first in case local clause is empty
909
+ */
910
+ while (! isKeyword (token, KEYWORD_do) &&
911
+ ! isKeyword (token, KEYWORD_once))
912
+ {
913
+ #ifndef TYPE_REFERENCE_TOOL
914
+ if (isType (token, TOKEN_IDENTIFIER))
915
+ makeEiffelLocalTag (token);
916
+ #endif
917
+ readToken (token);
918
+ if (isType (token, TOKEN_COLON))
919
+ parseEntityType (token);
920
+ }
921
+ }
922
+
923
+ static void findFeatureEnd (tokenInfo *const token)
924
+ {
925
+ boolean isFound = isKeyword (token, KEYWORD_is);
926
+ if (isFound)
927
+ readToken (token);
928
+ switch (token->keyword)
929
+ {
930
+ case KEYWORD_deferred:
931
+ case KEYWORD_do:
932
+ case KEYWORD_external:
933
+ case KEYWORD_local:
934
+ case KEYWORD_obsolete:
935
+ case KEYWORD_once:
936
+ case KEYWORD_require:
937
+ {
938
+ int depth = 1;
939
+
940
+ while (depth > 0)
941
+ {
942
+ #ifdef TYPE_REFERENCE_TOOL
943
+ if (isType (token, TOKEN_OPEN_BRACE))
944
+ {
945
+ readToken (token);
946
+ if (isType (token, TOKEN_IDENTIFIER))
947
+ parseType (token);
948
+ }
949
+ else if (isType (token, TOKEN_BANG))
950
+ {
951
+ readToken (token);
952
+ if (isType (token, TOKEN_IDENTIFIER))
953
+ parseType (token);
954
+ if (isType (token, TOKEN_BANG))
955
+ readToken (token);
956
+ }
957
+ else
958
+ #endif
959
+ switch (token->keyword)
960
+ {
961
+ case KEYWORD_check:
962
+ case KEYWORD_debug:
963
+ case KEYWORD_from:
964
+ case KEYWORD_if:
965
+ case KEYWORD_inspect:
966
+ ++depth;
967
+ break;
968
+
969
+ case KEYWORD_local:
970
+ parseLocal (token);
971
+ break;
972
+
973
+ case KEYWORD_end:
974
+ --depth;
975
+ break;
976
+
977
+ default:
978
+ break;
979
+ }
980
+ readToken (token);
981
+ }
982
+ break;
983
+ }
984
+
985
+ default:
986
+ /* is this a manifest constant? */
987
+ if (isFound || isType (token, TOKEN_OPERATOR)) {
988
+ if (isType (token, TOKEN_OPERATOR))
989
+ readToken (token);
990
+ readToken (token);
991
+ }
992
+ break;
993
+ }
994
+ }
995
+
996
+ static boolean readFeatureName (tokenInfo *const token)
997
+ {
998
+ boolean isFeatureName = FALSE;
999
+
1000
+ if (isKeyword (token, KEYWORD_frozen))
1001
+ readToken (token);
1002
+ if (isType (token, TOKEN_IDENTIFIER))
1003
+ isFeatureName = TRUE;
1004
+ else if (isKeyword (token, KEYWORD_assign)) /* legacy code */
1005
+ isFeatureName = TRUE;
1006
+ else if (isKeyword (token, KEYWORD_infix) ||
1007
+ isKeyword (token, KEYWORD_prefix))
1008
+ {
1009
+ readToken (token);
1010
+ if (isType (token, TOKEN_STRING))
1011
+ isFeatureName = TRUE;
1012
+ }
1013
+ return isFeatureName;
1014
+ }
1015
+
1016
+ static void parseArguments (tokenInfo *const token)
1017
+ {
1018
+ #ifndef TYPE_REFERENCE_TOOL
1019
+ findToken (token, TOKEN_CLOSE_PAREN);
1020
+ readToken (token);
1021
+ #else
1022
+ Assert (isType (token, TOKEN_OPEN_PAREN));
1023
+ readToken (token);
1024
+ do
1025
+ {
1026
+ if (isType (token, TOKEN_COLON))
1027
+ parseEntityType (token);
1028
+ else
1029
+ readToken (token);
1030
+ } while (! isType (token, TOKEN_CLOSE_PAREN));
1031
+ readToken (token);
1032
+ #endif
1033
+ }
1034
+
1035
+ static boolean parseFeature (tokenInfo *const token)
1036
+ {
1037
+ boolean found = FALSE;
1038
+ while (readFeatureName (token))
1039
+ {
1040
+ found = TRUE;
1041
+ #ifndef TYPE_REFERENCE_TOOL
1042
+ makeEiffelFeatureTag (token);
1043
+ #endif
1044
+ readToken (token);
1045
+ if (isType (token, TOKEN_COMMA))
1046
+ readToken (token);
1047
+ }
1048
+ if (found)
1049
+ {
1050
+ if (isKeyword (token, KEYWORD_alias)) {
1051
+ readToken (token);
1052
+ #ifndef TYPE_REFERENCE_TOOL
1053
+ if (isType (token, TOKEN_STRING))
1054
+ makeEiffelFeatureTag (token);
1055
+ #endif
1056
+ readToken (token);
1057
+ }
1058
+ if (isType (token, TOKEN_OPEN_PAREN)) /* arguments? */
1059
+ parseArguments (token);
1060
+ if (isType (token, TOKEN_COLON)) /* a query? */
1061
+ parseEntityType (token);
1062
+ if (isKeyword (token, KEYWORD_assign))
1063
+ {
1064
+ readToken (token);
1065
+ readToken (token);
1066
+ }
1067
+ if (isKeyword (token, KEYWORD_obsolete))
1068
+ {
1069
+ readToken (token);
1070
+ if (isType (token, TOKEN_STRING))
1071
+ readToken (token);
1072
+ }
1073
+ findFeatureEnd (token);
1074
+ }
1075
+ return found;
1076
+ }
1077
+
1078
+ static void parseExport (tokenInfo *const token)
1079
+ {
1080
+ token->isExported = TRUE;
1081
+ readToken (token);
1082
+ if (isType (token, TOKEN_OPEN_BRACE))
1083
+ {
1084
+ token->isExported = FALSE;
1085
+ while (! isType (token, TOKEN_CLOSE_BRACE))
1086
+ {
1087
+ if (isType (token, TOKEN_IDENTIFIER))
1088
+ token->isExported |= !isIdentifierMatch (token, "NONE");
1089
+ readToken (token);
1090
+ }
1091
+ readToken (token);
1092
+ }
1093
+ }
1094
+
1095
+ static void parseFeatureClauses (tokenInfo *const token)
1096
+ {
1097
+ Assert (isKeyword (token, KEYWORD_feature));
1098
+ do
1099
+ {
1100
+ if (isKeyword (token, KEYWORD_feature))
1101
+ parseExport (token);
1102
+ if (! isKeyword (token, KEYWORD_feature) &&
1103
+ ! isKeyword (token, KEYWORD_invariant) &&
1104
+ ! isKeyword (token, KEYWORD_indexing))
1105
+ {
1106
+ if (! parseFeature (token))
1107
+ readToken (token);
1108
+ }
1109
+ } while (! isKeyword (token, KEYWORD_end) &&
1110
+ ! isKeyword (token, KEYWORD_invariant) &&
1111
+ ! isKeyword (token, KEYWORD_indexing));
1112
+ }
1113
+
1114
+ static void parseRename (tokenInfo *const token)
1115
+ {
1116
+ Assert (isKeyword (token, KEYWORD_rename));
1117
+ do {
1118
+ readToken (token);
1119
+ if (readFeatureName (token))
1120
+ {
1121
+ readToken (token);
1122
+ if (isKeyword (token, KEYWORD_as))
1123
+ {
1124
+ readToken (token);
1125
+ if (readFeatureName (token))
1126
+ {
1127
+ #ifndef TYPE_REFERENCE_TOOL
1128
+ makeEiffelFeatureTag (token); /* renamed feature */
1129
+ #endif
1130
+ readToken (token);
1131
+ }
1132
+ }
1133
+ }
1134
+ } while (isType (token, TOKEN_COMMA));
1135
+ }
1136
+
1137
+ static void parseInherit (tokenInfo *const token)
1138
+ {
1139
+ Assert (isKeyword (token, KEYWORD_inherit));
1140
+ readToken (token);
1141
+ while (isType (token, TOKEN_IDENTIFIER))
1142
+ {
1143
+ parseType (token);
1144
+ if (isType (token, TOKEN_KEYWORD))
1145
+ {
1146
+ switch (token->keyword) /* check for feature adaptation */
1147
+ {
1148
+ case KEYWORD_rename:
1149
+ parseRename (token);
1150
+ case KEYWORD_export:
1151
+ case KEYWORD_undefine:
1152
+ case KEYWORD_redefine:
1153
+ case KEYWORD_select:
1154
+ findKeyword (token, KEYWORD_end);
1155
+ readToken (token);
1156
+ break;
1157
+
1158
+ case KEYWORD_end:
1159
+ readToken (token);
1160
+ break;
1161
+
1162
+ default: break;
1163
+ }
1164
+ }
1165
+ if (isType (token, TOKEN_SEMICOLON))
1166
+ readToken (token);
1167
+ }
1168
+ }
1169
+
1170
+ static void parseConvert (tokenInfo *const token)
1171
+ {
1172
+ Assert (isKeyword (token, KEYWORD_convert));
1173
+ do
1174
+ {
1175
+ readToken (token);
1176
+ if (! isType (token, TOKEN_IDENTIFIER))
1177
+ break;
1178
+ else if (isType (token, TOKEN_OPEN_PAREN))
1179
+ {
1180
+ while (! isType (token, TOKEN_CLOSE_PAREN))
1181
+ readToken (token);
1182
+ }
1183
+ else if (isType (token, TOKEN_COLON))
1184
+ {
1185
+ readToken (token);
1186
+ if (! isType (token, TOKEN_OPEN_BRACE))
1187
+ break;
1188
+ else while (! isType (token, TOKEN_CLOSE_BRACE))
1189
+ readToken (token);
1190
+ }
1191
+ } while (isType (token, TOKEN_COMMA));
1192
+ }
1193
+
1194
+ static void parseClass (tokenInfo *const token)
1195
+ {
1196
+ Assert (isKeyword (token, KEYWORD_class));
1197
+ readToken (token);
1198
+ if (isType (token, TOKEN_IDENTIFIER))
1199
+ {
1200
+ #ifndef TYPE_REFERENCE_TOOL
1201
+ makeEiffelClassTag (token);
1202
+ readToken (token);
1203
+ #else
1204
+ vStringCopy (token->className, token->string);
1205
+ vStringUpper (token->className);
1206
+ if (PrintClass)
1207
+ puts (vStringValue (token->className));
1208
+ if (! PrintReferences)
1209
+ exit (0);
1210
+ readToken (token);
1211
+ #endif
1212
+ }
1213
+
1214
+ do
1215
+ {
1216
+ if (isType (token, TOKEN_OPEN_BRACKET))
1217
+ parseGeneric (token, TRUE);
1218
+ else if (! isType (token, TOKEN_KEYWORD))
1219
+ readToken (token);
1220
+ else switch (token->keyword)
1221
+ {
1222
+ case KEYWORD_inherit: parseInherit (token); break;
1223
+ case KEYWORD_feature: parseFeatureClauses (token); break;
1224
+ case KEYWORD_convert: parseConvert (token); break;
1225
+ default: readToken (token); break;
1226
+ }
1227
+ } while (! isKeyword (token, KEYWORD_end));
1228
+ }
1229
+
1230
+ static void initialize (const langType language)
1231
+ {
1232
+ Lang_eiffel = language;
1233
+ buildEiffelKeywordHash ();
1234
+ }
1235
+
1236
+ static void findEiffelTags (void)
1237
+ {
1238
+ tokenInfo *const token = newToken ();
1239
+ exception_t exception;
1240
+
1241
+ exception = (exception_t) (setjmp (Exception));
1242
+ while (exception == ExceptionNone)
1243
+ {
1244
+ findKeyword (token, KEYWORD_class);
1245
+ parseClass (token);
1246
+ }
1247
+ deleteToken (token);
1248
+ }
1249
+
1250
+ #ifndef TYPE_REFERENCE_TOOL
1251
+
1252
+ extern parserDefinition* EiffelParser (void)
1253
+ {
1254
+ static const char *const extensions [] = { "e", NULL };
1255
+ parserDefinition* def = parserNew ("Eiffel");
1256
+ def->kinds = EiffelKinds;
1257
+ def->kindCount = KIND_COUNT (EiffelKinds);
1258
+ def->extensions = extensions;
1259
+ def->parser = findEiffelTags;
1260
+ def->initialize = initialize;
1261
+ return def;
1262
+ }
1263
+
1264
+ #else
1265
+
1266
+ static void findReferences (void)
1267
+ {
1268
+ ReferencedTypes = stringListNew ();
1269
+ GenericNames = stringListNew ();
1270
+ initialize (0);
1271
+
1272
+ findEiffelTags ();
1273
+
1274
+ stringListDelete (GenericNames);
1275
+ GenericNames = NULL;
1276
+ stringListDelete (ReferencedTypes);
1277
+ ReferencedTypes = NULL;
1278
+ }
1279
+
1280
+ static const char *const Usage =
1281
+ "Prints names of types referenced by an Eiffel language file.\n"
1282
+ "\n"
1283
+ "Usage: %s [-cdrs] [file_name | -]\n"
1284
+ "\n"
1285
+ "Options:\n"
1286
+ " -c Print class name of current file (on first line of output).\n"
1287
+ " -d Enable debug output.\n"
1288
+ " -r Print types referenced by current file (default unless -c).\n"
1289
+ " -s Include self-references.\n"
1290
+ "\n";
1291
+
1292
+ extern int main (int argc, char** argv)
1293
+ {
1294
+ int i;
1295
+ for (i = 1 ; argv [i] != NULL ; ++i)
1296
+ {
1297
+ const char *const arg = argv [i];
1298
+ if (arg [0] == '-')
1299
+ {
1300
+ int j;
1301
+ if (arg [1] == '\0')
1302
+ {
1303
+ File = stdin;
1304
+ FileName = "stdin";
1305
+ }
1306
+ else for (j = 1 ; arg [j] != '\0' ; ++j) switch (arg [j])
1307
+ {
1308
+ case 'c': PrintClass = 1; break;
1309
+ case 'r': PrintReferences = 1; break;
1310
+ case 's': SelfReferences = 1; break;
1311
+ case 'd': Debug = 1; break;
1312
+ default:
1313
+ fprintf (errout, "%s: unknown option: %c\n", argv [0], arg [1]);
1314
+ fprintf (errout, Usage, argv [0]);
1315
+ exit (1);
1316
+ break;
1317
+ }
1318
+ }
1319
+ else if (File != NULL)
1320
+ {
1321
+ fprintf (errout, Usage, argv [0]);
1322
+ exit (1);
1323
+ }
1324
+ else
1325
+ {
1326
+ FileName = arg;
1327
+ File = fopen (FileName, "r");
1328
+ if (File == NULL)
1329
+ {
1330
+ perror (argv [0]);
1331
+ exit (1);
1332
+ }
1333
+ }
1334
+ }
1335
+ if (! PrintClass)
1336
+ PrintReferences = 1;
1337
+ if (File == NULL)
1338
+ {
1339
+ fprintf (errout, Usage, argv [0]);
1340
+ exit (1);
1341
+ }
1342
+ else
1343
+ {
1344
+ findReferences ();
1345
+ fclose (File);
1346
+ }
1347
+ return 0;
1348
+ }
1349
+
1350
+ #endif
1351
+
1352
+ /* vi:set tabstop=4 shiftwidth=4: */