4 * Copyright (c) 1998-2002, Darren Hiebert
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains functions for generating tags for Eiffel language
16 #include "general.h" /* must always come first */
18 #ifdef TYPE_REFERENCE_TOOL
23 #include <ctype.h> /* to define tolower () */
30 #ifndef TYPE_REFERENCE_TOOL
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))
50 typedef enum eException
{ ExceptionNone
, ExceptionEOF
} exception_t
;
52 /* Used to specify type of keyword.
54 typedef enum eKeywordId
{
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
72 /* Used to determine whether keyword is valid for the token language and
75 typedef struct sKeywordDesc
{
80 typedef enum eTokenType
{
105 typedef struct sTokenInfo
{
111 vString
* featureName
;
118 static langType Lang_eiffel
;
120 #ifdef TYPE_REFERENCE_TOOL
122 static const char *FileName
;
124 static int PrintClass
;
125 static int PrintReferences
;
126 static int SelfReferences
;
128 static stringList
*GenericNames
;
129 static stringList
*ReferencedTypes
;
134 EKIND_CLASS
, EKIND_FEATURE
, EKIND_LOCAL
, EKIND_QUALIFIED_TAGS
137 static kindOption EiffelKinds
[] = {
138 { TRUE
, 'c', "class", "classes"},
139 { TRUE
, 'f', "feature", "features"},
140 { FALSE
, 'l', "local", "local entities"}
145 static langType Lang_eiffel
;
147 static jmp_buf Exception
;
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
}
211 * FUNCTION DEFINITIONS
214 static void buildEiffelKeywordHash (void)
216 const size_t count
= sizeof (EiffelKeywordTable
) /
217 sizeof (EiffelKeywordTable
[0]);
219 for (i
= 0 ; i
< count
; ++i
)
221 const keywordDesc
* const p
= &EiffelKeywordTable
[i
];
222 addKeyword (p
->name
, Lang_eiffel
, (int) p
->id
);
226 #ifdef TYPE_REFERENCE_TOOL
228 static void addGenericName (tokenInfo
*const token
)
230 vStringUpper (token
->string
);
231 if (vStringLength (token
->string
) > 0)
232 stringListAdd (GenericNames
, vStringNewCopy (token
->string
));
235 static boolean
isGeneric (tokenInfo
*const token
)
237 return (boolean
) stringListHas (GenericNames
, vStringValue (token
->string
));
240 static void reportType (tokenInfo
*const token
)
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
)))
248 printf ("%s\n", vStringValue (token
->string
));
249 stringListAdd (ReferencedTypes
, vStringNewCopy (token
->string
));
253 static int fileGetc (void)
265 if (Debug
> 0 && c
!= EOF
)
270 static int fileUngetc (c
)
272 return ungetc (c
, File
);
275 extern char *readLine (vString
*const vLine
, FILE *const fp
)
283 * Tag generation functions
286 static void makeEiffelClassTag (tokenInfo
*const token
)
288 if (EiffelKinds
[EKIND_CLASS
].enabled
)
290 const char *const name
= vStringValue (token
->string
);
293 initTagEntry (&e
, name
);
295 e
.kindName
= EiffelKinds
[EKIND_CLASS
].name
;
296 e
.kind
= EiffelKinds
[EKIND_CLASS
].letter
;
300 vStringCopy (token
->className
, token
->string
);
303 static void makeEiffelFeatureTag (tokenInfo
*const token
)
305 if (EiffelKinds
[EKIND_FEATURE
].enabled
&&
306 (token
->isExported
|| Option
.include
.fileScope
))
308 const char *const name
= vStringValue (token
->string
);
311 initTagEntry (&e
, name
);
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
);
321 if (Option
.include
.qualifiedTags
)
323 vString
* qualified
= vStringNewInit (vStringValue (token
->className
));
324 vStringPut (qualified
, '.');
325 vStringCat (qualified
, token
->string
);
326 e
.name
= vStringValue (qualified
);
328 vStringDelete (qualified
);
331 vStringCopy (token
->featureName
, token
->string
);
334 static void makeEiffelLocalTag (tokenInfo
*const token
)
336 if (EiffelKinds
[EKIND_LOCAL
].enabled
&& Option
.include
.fileScope
)
338 const char *const name
= vStringValue (token
->string
);
339 vString
* scope
= vStringNew ();
342 initTagEntry (&e
, name
);
344 e
.isFileScope
= TRUE
;
345 e
.kindName
= EiffelKinds
[EKIND_LOCAL
].name
;
346 e
.kind
= EiffelKinds
[EKIND_LOCAL
].letter
;
348 vStringCopy (scope
, token
->className
);
349 vStringPut (scope
, '.');
350 vStringCat (scope
, token
->featureName
);
352 e
.extensionFields
.scope
[0] = EiffelKinds
[EKIND_FEATURE
].name
;
353 e
.extensionFields
.scope
[1] = vStringValue (scope
);
356 vStringDelete (scope
);
366 static int skipToCharacter (const int c
)
373 } while (d
!= EOF
&& d
!= c
);
378 /* If a numeric is passed in 'c', this is used as the first digit of the
379 * numeric being parsed.
381 static vString
*parseInteger (int c
)
383 static vString
*string
= NULL
;
386 string
= vStringNew ();
387 vStringClear (string
);
393 vStringPut (string
, c
);
396 else if (! isdigit (c
))
398 while (c
!= EOF
&& (isdigit (c
) || c
== '_'))
400 vStringPut (string
, c
);
403 vStringTerminate (string
);
409 static vString
*parseNumeric (int c
)
411 static vString
*string
= NULL
;
414 string
= vStringNew ();
415 vStringCopy (string
, parseInteger (c
));
420 vStringPut (string
, c
);
421 vStringCat (string
, parseInteger ('\0'));
424 if (tolower (c
) == 'e')
426 vStringPut (string
, c
);
427 vStringCat (string
, parseInteger ('\0'));
429 else if (!isspace (c
))
432 vStringTerminate (string
);
437 static int parseEscapedCharacter (void)
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;
453 case 'Q': d
= 0x9F; break;
455 case 'Q': d
= '`'; break;
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;
470 case '\n': skipToCharacter ('%'); break;
474 vString
*string
= parseInteger ('\0');
475 const char *value
= vStringValue (string
);
476 const unsigned long ascii
= atol (value
);
479 if (c
== '/' && ascii
< 256)
489 static int parseCharacter (void)
495 result
= parseEscapedCharacter ();
499 skipToCharacter ('\n');
504 static void parseString (vString
*const string
)
506 boolean verbatim
= FALSE
;
507 boolean align
= FALSE
;
509 vString
*verbatimCloser
= NULL
;
510 vString
*lastLine
= NULL
;
524 end
= (boolean
) (strcmp (vStringValue (lastLine
),
525 vStringValue (verbatimCloser
)) == 0);
530 vStringClear (lastLine
);
531 if (prev
== '[' /* || prev == '{' */)
534 verbatimCloser
= vStringNew ();
535 lastLine
= vStringNew ();
537 vStringPut (verbatimCloser
, '}');
540 vStringPut (verbatimCloser
, ']');
543 vStringNCat (verbatimCloser
, string
, vStringLength (string
) - 1);
544 vStringClear (string
);
546 if (verbatim
&& align
)
554 c
= parseEscapedCharacter ();
557 vStringPut (string
, c
);
560 vStringPut (lastLine
, c
);
561 vStringTerminate (lastLine
);
566 vStringTerminate (string
);
569 /* Read a C identifier beginning with "firstChar" and places it into "name".
571 static void parseIdentifier (vString
*const string
, const int firstChar
)
577 vStringPut (string
, c
);
579 } while (isident (c
));
581 vStringTerminate (string
);
583 fileUngetc (c
); /* unget non-identifier character */
586 static void parseFreeOperator (vString
*const string
, const int firstChar
)
592 vStringPut (string
, c
);
596 vStringTerminate (string
);
598 fileUngetc (c
); /* unget non-identifier character */
601 static keywordId
analyzeToken (vString
*const name
)
603 static vString
*keyword
= NULL
;
607 keyword
= vStringNew ();
608 vStringCopyToLower (keyword
, name
);
609 id
= (keywordId
) lookupKeyword (vStringValue (keyword
), Lang_eiffel
);
614 static void readToken (tokenInfo
*const token
)
618 token
->type
= TOKEN_UNDEFINED
;
619 token
->keyword
= KEYWORD_NONE
;
620 vStringClear (token
->string
);
626 while (c
== '\t' || c
== ' ' || c
== '\n');
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;
648 case '=': token
->type
= TOKEN_OPERATOR
; break;
653 token
->type
= TOKEN_CONSTRAINT
;
654 else if (c
== '-') /* is this the start of a comment? */
656 skipToCharacter ('\n');
663 token
->type
= TOKEN_OPERATOR
;
671 token
->type
= TOKEN_OPERATOR
;
674 token
->type
= TOKEN_COLON
;
682 if (c
!= '=' && c
!= '>' && !isspace (c
))
684 token
->type
= TOKEN_OPERATOR
;
689 if (c
!= '=' && c
!= '>' && !isspace (c
))
691 token
->type
= TOKEN_OPERATOR
;
696 if (c
!= '/' && c
!= '=' && !isspace (c
))
698 token
->type
= TOKEN_OPERATOR
;
703 if (c
!= '\\' && !isspace (c
))
705 token
->type
= TOKEN_OPERATOR
;
709 token
->type
= TOKEN_STRING
;
710 parseString (token
->string
);
714 token
->type
= TOKEN_CHARACTER
;
721 parseIdentifier (token
->string
, c
);
722 token
->keyword
= analyzeToken (token
->string
);
723 if (isKeyword (token
, KEYWORD_NONE
))
724 token
->type
= TOKEN_IDENTIFIER
;
726 token
->type
= TOKEN_KEYWORD
;
728 else if (isdigit (c
))
730 vStringCat (token
->string
, parseNumeric (c
));
731 token
->type
= TOKEN_NUMERIC
;
733 else if (isFreeOperatorChar (c
))
735 parseFreeOperator (token
->string
, c
);
736 token
->type
= TOKEN_OPERATOR
;
740 token
->type
= TOKEN_UNDEFINED
;
741 Assert (! isType (token
, TOKEN_UNDEFINED
));
751 static boolean
isIdentifierMatch (
752 const tokenInfo
*const token
, const char *const name
)
754 return (boolean
) (isType (token
, TOKEN_IDENTIFIER
) &&
755 strcasecmp (vStringValue (token
->string
), name
) == 0);
758 static void findToken (tokenInfo
*const token
, const tokenType type
)
760 while (! isType (token
, type
))
764 static void findKeyword (tokenInfo
*const token
, const keywordId keyword
)
766 while (! isKeyword (token
, keyword
))
770 static void parseGeneric (tokenInfo
*const token
, boolean declaration __unused__
)
772 unsigned int depth
= 0;
773 #ifdef TYPE_REFERENCE_TOOL
774 boolean constraint
= FALSE
;
776 Assert (isType (token
, TOKEN_OPEN_BRACKET
));
779 if (isType (token
, TOKEN_OPEN_BRACKET
))
781 else if (isType (token
, TOKEN_CLOSE_BRACKET
))
783 #ifdef TYPE_REFERENCE_TOOL
784 else if (declaration
)
788 if (isType (token
, TOKEN_CONSTRAINT
))
790 else if (isKeyword (token
, KEYWORD_create
))
791 findKeyword (token
, KEYWORD_end
);
792 else if (isType (token
, TOKEN_IDENTIFIER
))
797 addGenericName (token
);
801 else if (isKeyword (token
, KEYWORD_like
))
803 else if (isType (token
, TOKEN_IDENTIFIER
))
808 if (isType (token
, TOKEN_OPEN_BRACKET
))
810 else if (isType (token
, TOKEN_IDENTIFIER
))
812 else if (isKeyword (token
, KEYWORD_like
))
820 static void parseType (tokenInfo
*const token
)
823 Assert (isType (token
, TOKEN_IDENTIFIER
));
824 #ifdef TYPE_REFERENCE_TOOL
827 bitType
= (boolean
)(strcmp ("BIT", vStringValue (token
->string
)) == 0);
829 if (bitType
&& isType (token
, TOKEN_NUMERIC
))
831 else if (isType (token
, TOKEN_OPEN_BRACKET
))
832 parseGeneric (token
, FALSE
);
835 static void parseEntityType (tokenInfo
*const token
)
837 Assert (isType (token
, TOKEN_COLON
));
840 if (isKeyword (token
, KEYWORD_expanded
))
843 /* Skip over the type name, with possible generic parameters.
845 if (isType (token
, TOKEN_IDENTIFIER
))
847 else if (isKeyword (token
, KEYWORD_like
))
850 if (isType (token
, TOKEN_IDENTIFIER
) ||
851 isKeyword (token
, KEYWORD_Current
))
857 static void parseLocal (tokenInfo
*const token
)
859 Assert (isKeyword (token
, KEYWORD_local
));
862 /* Check keyword first in case local clause is empty
864 while (! isKeyword (token
, KEYWORD_do
) &&
865 ! isKeyword (token
, KEYWORD_once
))
867 #ifndef TYPE_REFERENCE_TOOL
868 if (isType (token
, TOKEN_IDENTIFIER
))
869 makeEiffelLocalTag (token
);
872 if (isType (token
, TOKEN_COLON
))
875 if (isType (token
, TOKEN_IDENTIFIER
))
881 static void findFeatureEnd (tokenInfo
*const token
)
885 switch (token
->keyword
)
888 if (isType (token
, TOKEN_OPERATOR
)) /* sign of manifest constant */
890 readToken (token
); /* skip to next token after constant */
893 case KEYWORD_deferred
:
895 case KEYWORD_external
:
897 case KEYWORD_obsolete
:
899 case KEYWORD_require
:
905 #ifdef TYPE_REFERENCE_TOOL
906 if (isType (token
, TOKEN_OPEN_BRACE
))
909 if (isType (token
, TOKEN_IDENTIFIER
))
912 else if (isType (token
, TOKEN_BANG
))
915 if (isType (token
, TOKEN_IDENTIFIER
))
917 if (isType (token
, TOKEN_BANG
))
922 switch (token
->keyword
)
928 case KEYWORD_inspect
:
950 static boolean
readFeatureName (tokenInfo
*const token
)
952 boolean isFeatureName
= FALSE
;
954 if (isKeyword (token
, KEYWORD_frozen
))
956 if (isType (token
, TOKEN_IDENTIFIER
))
957 isFeatureName
= TRUE
;
958 else if (isKeyword (token
, KEYWORD_infix
) ||
959 isKeyword (token
, KEYWORD_prefix
))
962 if (isType (token
, TOKEN_STRING
))
963 isFeatureName
= TRUE
;
965 return isFeatureName
;
968 static void parseArguments (tokenInfo
*const token
)
970 #ifndef TYPE_REFERENCE_TOOL
971 findToken (token
, TOKEN_CLOSE_PAREN
);
974 Assert (isType (token
, TOKEN_OPEN_PAREN
));
978 if (! isType (token
, TOKEN_COLON
))
983 if (isType (token
, TOKEN_IDENTIFIER
))
986 } while (! isType (token
, TOKEN_CLOSE_PAREN
));
991 static boolean
parseFeature (tokenInfo
*const token
)
993 boolean found
= FALSE
;
994 while (readFeatureName (token
))
997 #ifndef TYPE_REFERENCE_TOOL
998 makeEiffelFeatureTag (token
);
1001 if (isType (token
, TOKEN_COMMA
))
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
))
1013 if (isType (token
, TOKEN_STRING
))
1016 if (isKeyword (token
, KEYWORD_is
))
1017 findFeatureEnd (token
);
1022 static void parseExport (tokenInfo
*const token
)
1024 token
->isExported
= TRUE
;
1026 if (isType (token
, TOKEN_OPEN_BRACE
))
1028 token
->isExported
= FALSE
;
1029 while (! isType (token
, TOKEN_CLOSE_BRACE
))
1031 if (isType (token
, TOKEN_IDENTIFIER
))
1032 token
->isExported
|= !isIdentifierMatch (token
, "NONE");
1039 static void parseFeatureClauses (tokenInfo
*const token
)
1041 Assert (isKeyword (token
, KEYWORD_feature
));
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
))
1050 if (! parseFeature (token
))
1053 } while (! isKeyword (token
, KEYWORD_end
) &&
1054 ! isKeyword (token
, KEYWORD_invariant
) &&
1055 ! isKeyword (token
, KEYWORD_indexing
));
1058 static void parseRename (tokenInfo
*const token
)
1062 if (readFeatureName (token
))
1065 if (isKeyword (token
, KEYWORD_as
))
1068 if (readFeatureName (token
))
1070 #ifndef TYPE_REFERENCE_TOOL
1071 makeEiffelFeatureTag (token
); /* renamed feature */
1077 } while (isType (token
, TOKEN_COMMA
));
1079 findKeyword (token
, KEYWORD_end
);
1084 static void parseInherit (tokenInfo
*const token
)
1086 Assert (isKeyword (token
, KEYWORD_inherit
));
1087 #ifdef TYPE_REFERENCE_TOOL
1089 while (isType (token
, TOKEN_IDENTIFIER
))
1092 if (isType (token
, TOKEN_KEYWORD
))
1094 switch (token
->keyword
) /* check for feature adaptation */
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
);
1109 while (isType (token
, TOKEN_IDENTIFIER
))
1112 switch (token
->keyword
) /* check for feature adaptation */
1114 case KEYWORD_rename
:
1115 parseRename (token
);
1116 if (isKeyword (token
, KEYWORD_end
))
1120 case KEYWORD_export
:
1121 case KEYWORD_undefine
:
1122 case KEYWORD_redefine
:
1123 case KEYWORD_select
:
1124 findKeyword (token
, KEYWORD_end
);
1138 static void parseClass (tokenInfo
*const token
)
1140 Assert (isKeyword (token
, KEYWORD_class
));
1142 if (isType (token
, TOKEN_IDENTIFIER
))
1144 #ifndef TYPE_REFERENCE_TOOL
1145 makeEiffelClassTag (token
);
1148 vStringCopy (token
->className
, token
->string
);
1149 vStringUpper (token
->className
);
1151 puts (vStringValue (token
->className
));
1152 if (! PrintReferences
)
1160 if (isType (token
, TOKEN_OPEN_BRACKET
))
1161 parseGeneric (token
, TRUE
);
1162 else if (! isType (token
, TOKEN_KEYWORD
))
1164 else switch (token
->keyword
)
1166 case KEYWORD_inherit
: parseInherit (token
); break;
1167 case KEYWORD_feature
: parseFeatureClauses (token
); break;
1168 default: readToken (token
); break;
1170 } while (! isKeyword (token
, KEYWORD_end
));
1173 static tokenInfo
*newToken (void)
1175 tokenInfo
*const token
= xMalloc (1, tokenInfo
);
1177 token
->type
= TOKEN_UNDEFINED
;
1178 token
->keyword
= KEYWORD_NONE
;
1179 token
->isExported
= TRUE
;
1181 token
->string
= vStringNew ();
1182 token
->className
= vStringNew ();
1183 token
->featureName
= vStringNew ();
1188 static void deleteToken (tokenInfo
*const token
)
1190 vStringDelete (token
->string
);
1191 vStringDelete (token
->className
);
1192 vStringDelete (token
->featureName
);
1197 static void initialize (const langType language
)
1199 Lang_eiffel
= language
;
1200 buildEiffelKeywordHash ();
1203 static void findEiffelTags (void)
1205 tokenInfo
*const token
= newToken ();
1206 exception_t exception
;
1208 exception
= (exception_t
) (setjmp (Exception
));
1209 while (exception
== ExceptionNone
)
1211 findKeyword (token
, KEYWORD_class
);
1214 deleteToken (token
);
1217 #ifndef TYPE_REFERENCE_TOOL
1219 extern parserDefinition
* EiffelParser (void)
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
;
1233 static void findReferences (void)
1235 ReferencedTypes
= stringListNew ();
1236 GenericNames
= stringListNew ();
1241 stringListDelete (GenericNames
);
1242 GenericNames
= NULL
;
1243 stringListDelete (ReferencedTypes
);
1244 ReferencedTypes
= NULL
;
1247 static const char *const Usage
=
1248 "Prints names of types referenced by an Eiffel language file.\n"
1250 "Usage: %s [-cdrs] [file_name | -]\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"
1259 extern int main (int argc
, char** argv
)
1262 for (i
= 1 ; argv
[i
] != NULL
; ++i
)
1264 const char *const arg
= argv
[i
];
1268 if (arg
[1] == '\0')
1273 else for (j
= 1 ; arg
[j
] != '\0' ; ++j
) switch (arg
[j
])
1275 case 'c': PrintClass
= 1; break;
1276 case 'r': PrintReferences
= 1; break;
1277 case 's': SelfReferences
= 1; break;
1278 case 'd': Debug
= 1; break;
1280 fprintf (errout
, "%s: unknown option: %c\n", argv
[0], arg
[1]);
1281 fprintf (errout
, Usage
, argv
[0]);
1286 else if (File
!= NULL
)
1288 fprintf (errout
, Usage
, argv
[0]);
1294 File
= fopen (FileName
, "r");
1303 PrintReferences
= 1;
1306 fprintf (errout
, Usage
, argv
[0]);
1319 /* vi:set tabstop=4 shiftwidth=4: */