~ubuntu-branches/ubuntu/lucid/codelite/lucid

« back to all changes in this revision

Viewing changes to sdk/ctags/eiffel.c

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2009-01-12 15:46:55 UTC
  • Revision ID: james.westby@ubuntu.com-20090112154655-sdynrljcb6u167yw
Tags: upstream-1.0.2674+dfsg
ImportĀ upstreamĀ versionĀ 1.0.2674+dfsg

Show diffs side-by-side

added added

removed removed

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