~ubuntu-branches/ubuntu/trusty/exuberant-ctags/trusty

1 by Colin Watson
Import upstream version 5.5.4
1
/*
1.1.3 by Colin Watson
Import upstream version 5.8
2
*   $Id: eiffel.c 706 2009-06-28 23:09:30Z dhiebert $
1 by Colin Watson
Import upstream version 5.5.4
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
*/
1.1.1 by Colin Watson
Import upstream version 5.6
16
#include "general.h"  /* must always come first */
1 by Colin Watson
Import upstream version 5.5.4
17
18
#ifdef TYPE_REFERENCE_TOOL
19
#include <stdio.h>
20
#endif
21
#include <string.h>
22
#include <limits.h>
1.1.1 by Colin Watson
Import upstream version 5.6
23
#include <ctype.h>  /* to define tolower () */
1 by Colin Watson
Import upstream version 5.5.4
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
*/
1.1.1 by Colin Watson
Import upstream version 5.6
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))
1 by Colin Watson
Import upstream version 5.5.4
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 {
1.1.1 by Colin Watson
Import upstream version 5.6
55
	KEYWORD_NONE = -1,
1.1.3 by Colin Watson
Import upstream version 5.8
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,
1.1.1 by Colin Watson
Import upstream version 5.6
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
1 by Colin Watson
Import upstream version 5.5.4
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 {
1.1.1 by Colin Watson
Import upstream version 5.6
77
	const char *name;
78
	keywordId id;
1 by Colin Watson
Import upstream version 5.5.4
79
} keywordDesc;
80
81
typedef enum eTokenType {
1.1.1 by Colin Watson
Import upstream version 5.6
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,
1.1.3 by Colin Watson
Import upstream version 5.8
101
	TOKEN_QUESTION,
102
	TOKEN_SEMICOLON,
1.1.1 by Colin Watson
Import upstream version 5.6
103
	TOKEN_SEPARATOR,
104
	TOKEN_STRING,
105
	TOKEN_TILDE
1 by Colin Watson
Import upstream version 5.5.4
106
} tokenType;
107
108
typedef struct sTokenInfo {
1.1.1 by Colin Watson
Import upstream version 5.6
109
	tokenType type;
110
	keywordId keyword;
111
	boolean   isExported;
112
	vString*  string;
113
	vString*  className;
114
	vString*  featureName;
1 by Colin Watson
Import upstream version 5.5.4
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 {
1.1.1 by Colin Watson
Import upstream version 5.6
137
	EKIND_CLASS, EKIND_FEATURE, EKIND_LOCAL, EKIND_QUALIFIED_TAGS
1 by Colin Watson
Import upstream version 5.5.4
138
} eiffelKind;
139
140
static kindOption EiffelKinds [] = {
1.1.1 by Colin Watson
Import upstream version 5.6
141
	{ TRUE,  'c', "class",   "classes"},
142
	{ TRUE,  'f', "feature", "features"},
143
	{ FALSE, 'l', "local",   "local entities"}
1 by Colin Watson
Import upstream version 5.5.4
144
};
145
146
#endif
147
148
static jmp_buf Exception;
149
150
static const keywordDesc EiffelKeywordTable [] = {
1.1.1 by Colin Watson
Import upstream version 5.6
151
	/* keyword          keyword ID */
152
	{ "alias",          KEYWORD_alias      },
153
	{ "all",            KEYWORD_all        },
154
	{ "and",            KEYWORD_and        },
155
	{ "as",             KEYWORD_as         },
1.1.3 by Colin Watson
Import upstream version 5.8
156
	{ "assign",         KEYWORD_assign     },
1.1.1 by Colin Watson
Import upstream version 5.6
157
	{ "check",          KEYWORD_check      },
158
	{ "class",          KEYWORD_class      },
1.1.2 by Colin Watson
Import upstream version 5.7
159
	{ "convert",        KEYWORD_convert    },
1.1.1 by Colin Watson
Import upstream version 5.6
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        }
1 by Colin Watson
Import upstream version 5.5.4
211
};
212
213
/*
214
*   FUNCTION DEFINITIONS
215
*/
216
217
static void buildEiffelKeywordHash (void)
218
{
1.1.1 by Colin Watson
Import upstream version 5.6
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
	}
1 by Colin Watson
Import upstream version 5.5.4
227
}
228
229
#ifdef TYPE_REFERENCE_TOOL
230
231
static void addGenericName (tokenInfo *const token)
232
{
1.1.1 by Colin Watson
Import upstream version 5.6
233
	vStringUpper (token->string);
234
	if (vStringLength (token->string) > 0)
235
		stringListAdd (GenericNames, vStringNewCopy (token->string));
1 by Colin Watson
Import upstream version 5.5.4
236
}
237
238
static boolean isGeneric (tokenInfo *const token)
239
{
1.1.1 by Colin Watson
Import upstream version 5.6
240
	return (boolean) stringListHas (GenericNames, vStringValue (token->string));
1 by Colin Watson
Import upstream version 5.5.4
241
}
242
243
static void reportType (tokenInfo *const token)
244
{
1.1.1 by Colin Watson
Import upstream version 5.6
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
	}
1 by Colin Watson
Import upstream version 5.5.4
254
}
255
256
static int fileGetc (void)
257
{
1.1.1 by Colin Watson
Import upstream version 5.6
258
	int c = getc (File);
259
	if (c == '\r')
1 by Colin Watson
Import upstream version 5.5.4
260
	{
1.1.1 by Colin Watson
Import upstream version 5.6
261
		c = getc (File);
262
		if (c != '\n')
263
		{
264
			ungetc (c, File);
265
			c = '\n';
266
		}
1 by Colin Watson
Import upstream version 5.5.4
267
	}
1.1.1 by Colin Watson
Import upstream version 5.6
268
	if (Debug > 0  &&  c != EOF)
269
		putc (c, errout);
270
	return c;
1 by Colin Watson
Import upstream version 5.5.4
271
}
272
273
static int fileUngetc (c)
274
{
1.1.1 by Colin Watson
Import upstream version 5.6
275
	return ungetc (c, File);
1 by Colin Watson
Import upstream version 5.5.4
276
}
277
278
extern char *readLine (vString *const vLine, FILE *const fp)
279
{
1.1.1 by Colin Watson
Import upstream version 5.6
280
	return NULL;
1 by Colin Watson
Import upstream version 5.5.4
281
}
282
283
#else
284
285
/*
286
*   Tag generation functions
287
*/
288
289
static void makeEiffelClassTag (tokenInfo *const token)
290
{
1.1.1 by Colin Watson
Import upstream version 5.6
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);
1 by Colin Watson
Import upstream version 5.5.4
304
}
305
306
static void makeEiffelFeatureTag (tokenInfo *const token)
307
{
1.1.1 by Colin Watson
Import upstream version 5.6
308
	if (EiffelKinds [EKIND_FEATURE].enabled  &&
309
		(token->isExported  ||  Option.include.fileScope))
1 by Colin Watson
Import upstream version 5.5.4
310
	{
1.1.1 by Colin Watson
Import upstream version 5.6
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
		}
1 by Colin Watson
Import upstream version 5.5.4
333
	}
1.1.1 by Colin Watson
Import upstream version 5.6
334
	vStringCopy (token->featureName, token->string);
1 by Colin Watson
Import upstream version 5.5.4
335
}
336
337
static void makeEiffelLocalTag (tokenInfo *const token)
338
{
1.1.1 by Colin Watson
Import upstream version 5.6
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
	}
1 by Colin Watson
Import upstream version 5.5.4
361
}
362
363
#endif
364
365
/*
366
*   Parsing functions
367
*/
368
369
static int skipToCharacter (const int c)
370
{
1.1.1 by Colin Watson
Import upstream version 5.6
371
	int d;
372
373
	do
374
	{
375
		d = fileGetc ();
376
	} while (d != EOF  &&  d != c);
377
378
	return d;
1 by Colin Watson
Import upstream version 5.5.4
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
{
1.1.2 by Colin Watson
Import upstream version 5.7
386
	vString *string = vStringNew ();
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1 by Colin Watson
Import upstream version 5.5.4
406
}
407
408
static vString *parseNumeric (int c)
409
{
1.1.2 by Colin Watson
Import upstream version 5.7
410
	vString *string = vStringNew ();
411
	vString *integer = parseInteger (c);
412
	vStringCopy (string, integer);
413
	vStringDelete (integer);
1.1.1 by Colin Watson
Import upstream version 5.6
414
1 by Colin Watson
Import upstream version 5.5.4
415
	c = fileGetc ();
1.1.1 by Colin Watson
Import upstream version 5.6
416
	if (c == '.')
417
	{
1.1.2 by Colin Watson
Import upstream version 5.7
418
		integer = parseInteger ('\0');
1.1.1 by Colin Watson
Import upstream version 5.6
419
		vStringPut (string, c);
1.1.2 by Colin Watson
Import upstream version 5.7
420
		vStringCat (string, integer);
421
		vStringDelete (integer);
1.1.1 by Colin Watson
Import upstream version 5.6
422
		c = fileGetc ();
423
	}
424
	if (tolower (c) == 'e')
425
	{
1.1.2 by Colin Watson
Import upstream version 5.7
426
		integer = parseInteger ('\0');
1.1.1 by Colin Watson
Import upstream version 5.6
427
		vStringPut (string, c);
1.1.2 by Colin Watson
Import upstream version 5.7
428
		vStringCat (string, integer);
429
		vStringDelete (integer);
1.1.1 by Colin Watson
Import upstream version 5.6
430
	}
431
	else if (!isspace (c))
432
		fileUngetc (c);
433
434
	vStringTerminate (string);
435
436
	return string;
1 by Colin Watson
Import upstream version 5.5.4
437
}
438
439
static int parseEscapedCharacter (void)
440
{
1.1.1 by Colin Watson
Import upstream version 5.6
441
	int d = '\0';
442
	int c = fileGetc ();
1 by Colin Watson
Import upstream version 5.5.4
443
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1 by Colin Watson
Import upstream version 5.5.4
454
#ifdef QDOS
1.1.1 by Colin Watson
Import upstream version 5.6
455
		case 'Q':  d = 0x9F;  break;
1 by Colin Watson
Import upstream version 5.5.4
456
#else
1.1.1 by Colin Watson
Import upstream version 5.6
457
		case 'Q':  d = '`';   break;
1 by Colin Watson
Import upstream version 5.5.4
458
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
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);
1.1.2 by Colin Watson
Import upstream version 5.7
479
			vStringDelete (string);
1.1.1 by Colin Watson
Import upstream version 5.6
480
481
			c = fileGetc ();
482
			if (c == '/'  &&  ascii < 256)
483
				d = ascii;
484
			break;
485
		}
486
487
		default: break;
1 by Colin Watson
Import upstream version 5.5.4
488
	}
1.1.1 by Colin Watson
Import upstream version 5.6
489
	return d;
1 by Colin Watson
Import upstream version 5.5.4
490
}
491
492
static int parseCharacter (void)
493
{
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1 by Colin Watson
Import upstream version 5.5.4
505
}
506
507
static void parseString (vString *const string)
508
{
1.1.1 by Colin Watson
Import upstream version 5.6
509
	boolean verbatim = FALSE;
510
	boolean align = FALSE;
511
	boolean end = FALSE;
1.1.2 by Colin Watson
Import upstream version 5.7
512
	vString *verbatimCloser = vStringNew ();
513
	vString *lastLine = vStringNew ();
1.1.1 by Colin Watson
Import upstream version 5.6
514
	int prev = '\0';
515
	int c;
1 by Colin Watson
Import upstream version 5.5.4
516
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1.1.2 by Colin Watson
Import upstream version 5.7
537
				vStringClear (verbatimCloser);
538
				vStringClear (lastLine);
1.1.1 by Colin Watson
Import upstream version 5.6
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);
1.1.2 by Colin Watson
Import upstream version 5.7
570
	vStringDelete (lastLine);
571
	vStringDelete (verbatimCloser);
1 by Colin Watson
Import upstream version 5.5.4
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
{
1.1.1 by Colin Watson
Import upstream version 5.6
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 */
1 by Colin Watson
Import upstream version 5.5.4
589
}
590
591
static void parseFreeOperator (vString *const string, const int firstChar)
592
{
1.1.1 by Colin Watson
Import upstream version 5.6
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 */
1 by Colin Watson
Import upstream version 5.5.4
604
}
605
1.1.3 by Colin Watson
Import upstream version 5.8
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);
1 by Colin Watson
Import upstream version 5.5.4
639
}
640
641
static void readToken (tokenInfo *const token)
642
{
1.1.1 by Colin Watson
Import upstream version 5.6
643
	int c;
1 by Colin Watson
Import upstream version 5.5.4
644
1.1.1 by Colin Watson
Import upstream version 5.6
645
	token->type    = TOKEN_UNDEFINED;
646
	token->keyword = KEYWORD_NONE;
647
	vStringClear (token->string);
1 by Colin Watson
Import upstream version 5.5.4
648
649
getNextChar:
650
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1.1.3 by Colin Watson
Import upstream version 5.8
658
		case ';':  token->type = TOKEN_SEMICOLON;          break;
1.1.1 by Colin Watson
Import upstream version 5.6
659
		case '!':  token->type = TOKEN_BANG;               break;
1.1.3 by Colin Watson
Import upstream version 5.8
660
		case '}':  token->type = TOKEN_CLOSE_BRACE;        break;
661
		case ']':  token->type = TOKEN_CLOSE_BRACKET;      break;
1.1.1 by Colin Watson
Import upstream version 5.6
662
		case ')':  token->type = TOKEN_CLOSE_PAREN;        break;
663
		case ',':  token->type = TOKEN_COMMA;              break;
1.1.3 by Colin Watson
Import upstream version 5.8
664
		case '$':  token->type = TOKEN_DOLLAR;             break;
1.1.1 by Colin Watson
Import upstream version 5.6
665
		case '.':  token->type = TOKEN_DOT;                break;
1.1.3 by Colin Watson
Import upstream version 5.8
666
		case '{':  token->type = TOKEN_OPEN_BRACE;         break;
1.1.1 by Colin Watson
Import upstream version 5.6
667
		case '[':  token->type = TOKEN_OPEN_BRACKET;       break;
1.1.3 by Colin Watson
Import upstream version 5.8
668
		case '(':  token->type = TOKEN_OPEN_PAREN;         break;
1.1.1 by Colin Watson
Import upstream version 5.6
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 ':':
1.1.3 by Colin Watson
Import upstream version 5.8
696
		{
697
			int c2 = fileGetc ();
698
			if (c2 == '=')
1.1.1 by Colin Watson
Import upstream version 5.6
699
				token->type = TOKEN_OPERATOR;
700
			else
701
			{
1.1.3 by Colin Watson
Import upstream version 5.8
702
				if (!isspace (c2))
703
					fileUngetc (c2);
704
				if (c == ':')
705
					token->type = TOKEN_COLON;
706
				else
707
					token->type = TOKEN_QUESTION;
1.1.1 by Colin Watson
Import upstream version 5.6
708
			}
709
			break;
1.1.3 by Colin Watson
Import upstream version 5.8
710
		}
1.1.1 by Colin Watson
Import upstream version 5.6
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);
1.1.3 by Colin Watson
Import upstream version 5.8
754
				token->keyword = analyzeToken (token->string, Lang_eiffel);
1.1.1 by Colin Watson
Import upstream version 5.6
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
			{
1.1.2 by Colin Watson
Import upstream version 5.7
762
				vString* numeric = parseNumeric (c);
763
				vStringCat (token->string, numeric);
764
				vStringDelete (numeric);
1.1.1 by Colin Watson
Import upstream version 5.6
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
	}
1 by Colin Watson
Import upstream version 5.5.4
779
}
780
781
/*
782
*   Scanning functions
783
*/
784
1.1.1 by Colin Watson
Import upstream version 5.6
785
static boolean isIdentifierMatch (
786
		const tokenInfo *const token, const char *const name)
1 by Colin Watson
Import upstream version 5.5.4
787
{
1.1.1 by Colin Watson
Import upstream version 5.6
788
	return (boolean) (isType (token, TOKEN_IDENTIFIER)  &&
789
		strcasecmp (vStringValue (token->string), name) == 0);
1 by Colin Watson
Import upstream version 5.5.4
790
}
791
792
static void findToken (tokenInfo *const token, const tokenType type)
793
{
1.1.1 by Colin Watson
Import upstream version 5.6
794
	while (! isType (token, type))
795
		readToken (token);
1 by Colin Watson
Import upstream version 5.5.4
796
}
797
798
static void findKeyword (tokenInfo *const token, const keywordId keyword)
799
{
1.1.1 by Colin Watson
Import upstream version 5.6
800
	while (! isKeyword (token, keyword))
801
		readToken (token);
1 by Colin Watson
Import upstream version 5.5.4
802
}
803
1.1.3 by Colin Watson
Import upstream version 5.8
804
static boolean parseType (tokenInfo *const token);
805
1 by Colin Watson
Import upstream version 5.5.4
806
static void parseGeneric (tokenInfo *const token, boolean declaration __unused__)
807
{
1.1.1 by Colin Watson
Import upstream version 5.6
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))
1.1.3 by Colin Watson
Import upstream version 5.8
816
		{
1.1.1 by Colin Watson
Import upstream version 5.6
817
			++depth;
1.1.3 by Colin Watson
Import upstream version 5.8
818
			readToken (token);
819
		}
1.1.1 by Colin Watson
Import upstream version 5.6
820
		else if (isType (token, TOKEN_CLOSE_BRACKET))
1.1.3 by Colin Watson
Import upstream version 5.8
821
		{
1.1.1 by Colin Watson
Import upstream version 5.6
822
			--depth;
1.1.3 by Colin Watson
Import upstream version 5.8
823
			readToken (token);
824
		}
1.1.1 by Colin Watson
Import upstream version 5.6
825
#ifdef TYPE_REFERENCE_TOOL
826
		else if (declaration)
827
		{
1.1.3 by Colin Watson
Import upstream version 5.8
828
			boolean advanced = FALSE;
1.1.1 by Colin Watson
Import upstream version 5.6
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)
1.1.3 by Colin Watson
Import upstream version 5.8
838
						advanced = parseType (token);
1.1.1 by Colin Watson
Import upstream version 5.6
839
					else
840
						addGenericName (token);
841
					constraint = FALSE;
842
				}
843
			}
1.1.3 by Colin Watson
Import upstream version 5.8
844
			else if (isType (token, TOKEN_IDENTIFIER))
845
				advanced = parseType (token);
846
			if (! advanced)
1.1.1 by Colin Watson
Import upstream version 5.6
847
				readToken (token);
848
		}
1.1.3 by Colin Watson
Import upstream version 5.8
849
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
850
		else
1.1.3 by Colin Watson
Import upstream version 5.8
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
1.1.1 by Colin Watson
Import upstream version 5.6
883
			if (isType (token, TOKEN_OPEN_BRACKET))
1.1.3 by Colin Watson
Import upstream version 5.8
884
				parseGeneric (token, FALSE);
885
			else if ((strcmp ("BIT", vStringValue (id->string)) == 0))
886
				readToken (token);  /* read token after number of bits */
1.1.1 by Colin Watson
Import upstream version 5.6
887
		}
1.1.3 by Colin Watson
Import upstream version 5.8
888
	}
889
	deleteToken (id);
890
	return TRUE;
1 by Colin Watson
Import upstream version 5.5.4
891
}
892
893
static void parseEntityType (tokenInfo *const token)
894
{
1.1.1 by Colin Watson
Import upstream version 5.6
895
	Assert (isType (token, TOKEN_COLON));
896
	readToken (token);
897
1.1.3 by Colin Watson
Import upstream version 5.8
898
	if (isType (token, TOKEN_BANG) || isType (token, TOKEN_QUESTION))
899
		readToken (token);  /* skip over '!' or '?' */
900
	parseType (token);
1 by Colin Watson
Import upstream version 5.5.4
901
}
902
903
static void parseLocal (tokenInfo *const token)
904
{
1.1.1 by Colin Watson
Import upstream version 5.6
905
	Assert (isKeyword (token, KEYWORD_local));
906
	readToken (token);
1 by Colin Watson
Import upstream version 5.5.4
907
1.1.1 by Colin Watson
Import upstream version 5.6
908
	/*  Check keyword first in case local clause is empty
909
	 */
910
	while (! isKeyword (token, KEYWORD_do)  &&
911
		   ! isKeyword (token, KEYWORD_once))
912
	{
1 by Colin Watson
Import upstream version 5.5.4
913
#ifndef TYPE_REFERENCE_TOOL
1.1.1 by Colin Watson
Import upstream version 5.6
914
		if (isType (token, TOKEN_IDENTIFIER))
915
			makeEiffelLocalTag (token);
1 by Colin Watson
Import upstream version 5.5.4
916
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
917
		readToken (token);
918
		if (isType (token, TOKEN_COLON))
1.1.3 by Colin Watson
Import upstream version 5.8
919
			parseEntityType (token);
1 by Colin Watson
Import upstream version 5.5.4
920
	}
921
}
922
923
static void findFeatureEnd (tokenInfo *const token)
924
{
1.1.3 by Colin Watson
Import upstream version 5.8
925
	boolean isFound = isKeyword (token, KEYWORD_is);
926
	if (isFound)
927
		readToken (token);
1.1.1 by Colin Watson
Import upstream version 5.6
928
	switch (token->keyword)
1 by Colin Watson
Import upstream version 5.5.4
929
	{
1.1.1 by Colin Watson
Import upstream version 5.6
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
			{
1 by Colin Watson
Import upstream version 5.5.4
942
#ifdef TYPE_REFERENCE_TOOL
1.1.1 by Colin Watson
Import upstream version 5.6
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
1 by Colin Watson
Import upstream version 5.5.4
958
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
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
			}
1 by Colin Watson
Import upstream version 5.5.4
982
			break;
983
		}
1.1.3 by Colin Watson
Import upstream version 5.8
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;
1 by Colin Watson
Import upstream version 5.5.4
993
	}
994
}
995
996
static boolean readFeatureName (tokenInfo *const token)
997
{
1.1.1 by Colin Watson
Import upstream version 5.6
998
	boolean isFeatureName = FALSE;
1 by Colin Watson
Import upstream version 5.5.4
999
1.1.1 by Colin Watson
Import upstream version 5.6
1000
	if (isKeyword (token, KEYWORD_frozen))
1001
		readToken (token);
1002
	if (isType (token, TOKEN_IDENTIFIER))
1003
		isFeatureName = TRUE;
1.1.3 by Colin Watson
Import upstream version 5.8
1004
	else if (isKeyword (token, KEYWORD_assign))  /* legacy code */
1005
		isFeatureName = TRUE;
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1 by Colin Watson
Import upstream version 5.5.4
1014
}
1015
1016
static void parseArguments (tokenInfo *const token)
1017
{
1018
#ifndef TYPE_REFERENCE_TOOL
1.1.1 by Colin Watson
Import upstream version 5.6
1019
	findToken (token, TOKEN_CLOSE_PAREN);
1020
	readToken (token);
1 by Colin Watson
Import upstream version 5.5.4
1021
#else
1.1.1 by Colin Watson
Import upstream version 5.6
1022
	Assert (isType (token, TOKEN_OPEN_PAREN));
1023
	readToken (token);
1024
	do
1 by Colin Watson
Import upstream version 5.5.4
1025
	{
1.1.3 by Colin Watson
Import upstream version 5.8
1026
		if (isType (token, TOKEN_COLON))
1027
			parseEntityType (token);
1.1.1 by Colin Watson
Import upstream version 5.6
1028
		else
1029
			readToken (token);
1030
	} while (! isType (token, TOKEN_CLOSE_PAREN));
1031
	readToken (token);
1 by Colin Watson
Import upstream version 5.5.4
1032
#endif
1033
}
1034
1035
static boolean parseFeature (tokenInfo *const token)
1036
{
1.1.1 by Colin Watson
Import upstream version 5.6
1037
	boolean found = FALSE;
1038
	while (readFeatureName (token))
1039
	{
1040
		found = TRUE;
1 by Colin Watson
Import upstream version 5.5.4
1041
#ifndef TYPE_REFERENCE_TOOL
1.1.1 by Colin Watson
Import upstream version 5.6
1042
		makeEiffelFeatureTag (token);
1 by Colin Watson
Import upstream version 5.5.4
1043
#endif
1044
		readToken (token);
1.1.1 by Colin Watson
Import upstream version 5.6
1045
		if (isType (token, TOKEN_COMMA))
1046
			readToken (token);
1047
	}
1048
	if (found)
1049
	{
1.1.3 by Colin Watson
Import upstream version 5.8
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
		}
1.1.1 by Colin Watson
Import upstream version 5.6
1058
		if (isType (token, TOKEN_OPEN_PAREN))  /* arguments? */
1059
			parseArguments (token);
1060
		if (isType (token, TOKEN_COLON))       /* a query? */
1061
			parseEntityType (token);
1.1.3 by Colin Watson
Import upstream version 5.8
1062
		if (isKeyword (token, KEYWORD_assign))
1063
		{
1064
			readToken (token);
1065
			readToken (token);
1066
		}
1.1.1 by Colin Watson
Import upstream version 5.6
1067
		if (isKeyword (token, KEYWORD_obsolete))
1068
		{
1069
			readToken (token);
1070
			if (isType (token, TOKEN_STRING))
1071
				readToken (token);
1072
		}
1.1.3 by Colin Watson
Import upstream version 5.8
1073
		findFeatureEnd (token);
1.1.1 by Colin Watson
Import upstream version 5.6
1074
	}
1075
	return found;
1 by Colin Watson
Import upstream version 5.5.4
1076
}
1077
1078
static void parseExport (tokenInfo *const token)
1079
{
1.1.1 by Colin Watson
Import upstream version 5.6
1080
	token->isExported = TRUE;
1081
	readToken (token);
1082
	if (isType (token, TOKEN_OPEN_BRACE))
1 by Colin Watson
Import upstream version 5.5.4
1083
	{
1.1.1 by Colin Watson
Import upstream version 5.6
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);
1 by Colin Watson
Import upstream version 5.5.4
1092
	}
1093
}
1094
1095
static void parseFeatureClauses (tokenInfo *const token)
1096
{
1.1.1 by Colin Watson
Import upstream version 5.6
1097
	Assert (isKeyword (token, KEYWORD_feature));
1098
	do
1 by Colin Watson
Import upstream version 5.5.4
1099
	{
1.1.1 by Colin Watson
Import upstream version 5.6
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));
1 by Colin Watson
Import upstream version 5.5.4
1112
}
1113
1114
static void parseRename (tokenInfo *const token)
1115
{
1.1.3 by Colin Watson
Import upstream version 5.8
1116
	Assert (isKeyword (token, KEYWORD_rename));
1.1.1 by Colin Watson
Import upstream version 5.6
1117
	do {
1 by Colin Watson
Import upstream version 5.5.4
1118
		readToken (token);
1119
		if (readFeatureName (token))
1120
		{
1.1.1 by Colin Watson
Import upstream version 5.6
1121
			readToken (token);
1122
			if (isKeyword (token, KEYWORD_as))
1123
			{
1124
				readToken (token);
1125
				if (readFeatureName (token))
1126
				{
1 by Colin Watson
Import upstream version 5.5.4
1127
#ifndef TYPE_REFERENCE_TOOL
1.1.1 by Colin Watson
Import upstream version 5.6
1128
					makeEiffelFeatureTag (token);  /* renamed feature */
1 by Colin Watson
Import upstream version 5.5.4
1129
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
1130
					readToken (token);
1131
				}
1132
			}
1 by Colin Watson
Import upstream version 5.5.4
1133
		}
1.1.1 by Colin Watson
Import upstream version 5.6
1134
	} while (isType (token, TOKEN_COMMA));
1 by Colin Watson
Import upstream version 5.5.4
1135
}
1136
1137
static void parseInherit (tokenInfo *const token)
1138
{
1.1.1 by Colin Watson
Import upstream version 5.6
1139
	Assert (isKeyword (token, KEYWORD_inherit));
1140
	readToken (token);
1141
	while (isType (token, TOKEN_IDENTIFIER))
1 by Colin Watson
Import upstream version 5.5.4
1142
	{
1.1.1 by Colin Watson
Import upstream version 5.6
1143
		parseType (token);
1144
		if (isType (token, TOKEN_KEYWORD))
1145
		{
1146
			switch (token->keyword)  /* check for feature adaptation */
1147
			{
1148
				case KEYWORD_rename:
1.1.3 by Colin Watson
Import upstream version 5.8
1149
					parseRename (token);
1.1.1 by Colin Watson
Import upstream version 5.6
1150
				case KEYWORD_export:
1151
				case KEYWORD_undefine:
1152
				case KEYWORD_redefine:
1153
				case KEYWORD_select:
1154
					findKeyword (token, KEYWORD_end);
1155
					readToken (token);
1.1.3 by Colin Watson
Import upstream version 5.8
1156
					break;
1157
1158
				case KEYWORD_end:
1159
					readToken (token);
1160
					break;
1161
1.1.1 by Colin Watson
Import upstream version 5.6
1162
				default: break;
1163
			}
1164
		}
1.1.3 by Colin Watson
Import upstream version 5.8
1165
		if (isType (token, TOKEN_SEMICOLON))
1166
			readToken (token);
1167
	}
1 by Colin Watson
Import upstream version 5.5.4
1168
}
1169
1.1.2 by Colin Watson
Import upstream version 5.7
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
1 by Colin Watson
Import upstream version 5.5.4
1194
static void parseClass (tokenInfo *const token)
1195
{
1.1.1 by Colin Watson
Import upstream version 5.6
1196
	Assert (isKeyword (token, KEYWORD_class));
1197
	readToken (token);
1198
	if (isType (token, TOKEN_IDENTIFIER))
1199
	{
1 by Colin Watson
Import upstream version 5.5.4
1200
#ifndef TYPE_REFERENCE_TOOL
1.1.1 by Colin Watson
Import upstream version 5.6
1201
		makeEiffelClassTag (token);
1202
		readToken (token);
1 by Colin Watson
Import upstream version 5.5.4
1203
#else
1.1.1 by Colin Watson
Import upstream version 5.6
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);
1 by Colin Watson
Import upstream version 5.5.4
1211
#endif
1212
	}
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1.1.2 by Colin Watson
Import upstream version 5.7
1224
			case KEYWORD_convert:  parseConvert (token);        break;
1.1.1 by Colin Watson
Import upstream version 5.6
1225
			default:               readToken (token);           break;
1226
		}
1227
	} while (! isKeyword (token, KEYWORD_end));
1 by Colin Watson
Import upstream version 5.5.4
1228
}
1229
1230
static void initialize (const langType language)
1231
{
1.1.1 by Colin Watson
Import upstream version 5.6
1232
	Lang_eiffel = language;
1233
	buildEiffelKeywordHash ();
1 by Colin Watson
Import upstream version 5.5.4
1234
}
1235
1236
static void findEiffelTags (void)
1237
{
1.1.1 by Colin Watson
Import upstream version 5.6
1238
	tokenInfo *const token = newToken ();
1239
	exception_t exception;
1 by Colin Watson
Import upstream version 5.5.4
1240
1.1.1 by Colin Watson
Import upstream version 5.6
1241
	exception = (exception_t) (setjmp (Exception));
1242
	while (exception == ExceptionNone)
1243
	{
1244
		findKeyword (token, KEYWORD_class);
1245
		parseClass (token);
1246
	}
1247
	deleteToken (token);
1 by Colin Watson
Import upstream version 5.5.4
1248
}
1249
1250
#ifndef TYPE_REFERENCE_TOOL
1251
1252
extern parserDefinition* EiffelParser (void)
1253
{
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1 by Colin Watson
Import upstream version 5.5.4
1262
}
1263
1264
#else
1265
1266
static void findReferences (void)
1267
{
1.1.1 by Colin Watson
Import upstream version 5.6
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;
1 by Colin Watson
Import upstream version 5.5.4
1278
}
1279
1280
static const char *const Usage =
1.1.1 by Colin Watson
Import upstream version 5.6
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";
1 by Colin Watson
Import upstream version 5.5.4
1291
1.1.1 by Colin Watson
Import upstream version 5.6
1292
extern int main (int argc, char** argv)
1 by Colin Watson
Import upstream version 5.5.4
1293
{
1.1.1 by Colin Watson
Import upstream version 5.6
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]);
1 by Colin Watson
Import upstream version 5.5.4
1340
		exit (1);
1.1.1 by Colin Watson
Import upstream version 5.6
1341
	}
1342
	else
1343
	{
1344
		findReferences ();
1345
		fclose (File);
1346
	}
1347
	return 0;
1 by Colin Watson
Import upstream version 5.5.4
1348
}
1349
1350
#endif
1351
1.1.1 by Colin Watson
Import upstream version 5.6
1352
/* vi:set tabstop=4 shiftwidth=4: */