2 * $Id: eiffel.c 748 2009-11-06 02:44:42Z dhiebert $
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
,
57 KEYWORD_as
, KEYWORD_assign
, KEYWORD_attached
,
58 KEYWORD_check
, KEYWORD_class
, KEYWORD_convert
, KEYWORD_create
,
59 KEYWORD_creation
, KEYWORD_Current
,
60 KEYWORD_debug
, KEYWORD_deferred
, KEYWORD_detachable
, KEYWORD_do
,
61 KEYWORD_else
, KEYWORD_elseif
, KEYWORD_end
, KEYWORD_ensure
,
62 KEYWORD_expanded
, KEYWORD_export
, KEYWORD_external
,
63 KEYWORD_false
, KEYWORD_feature
, KEYWORD_from
, KEYWORD_frozen
,
64 KEYWORD_if
, KEYWORD_implies
,
65 KEYWORD_indexing
, KEYWORD_infix
, KEYWORD_inherit
, KEYWORD_inspect
,
66 KEYWORD_invariant
, KEYWORD_is
, KEYWORD_like
, KEYWORD_local
,
67 KEYWORD_loop
, KEYWORD_not
, KEYWORD_obsolete
, KEYWORD_old
, KEYWORD_once
,
68 KEYWORD_or
, KEYWORD_prefix
, KEYWORD_redefine
, KEYWORD_rename
,
69 KEYWORD_require
, KEYWORD_rescue
, KEYWORD_Result
, KEYWORD_retry
,
70 KEYWORD_select
, KEYWORD_separate
, KEYWORD_strip
, KEYWORD_then
,
71 KEYWORD_true
, KEYWORD_undefine
, KEYWORD_unique
, KEYWORD_until
,
72 KEYWORD_variant
, KEYWORD_when
, KEYWORD_xor
75 /* Used to determine whether keyword is valid for the token language and
78 typedef struct sKeywordDesc
{
83 typedef enum eTokenType
{
110 typedef struct sTokenInfo
{
116 vString
* featureName
;
123 static langType Lang_eiffel
;
125 #ifdef TYPE_REFERENCE_TOOL
127 static const char *FileName
;
129 static int PrintClass
;
130 static int PrintReferences
;
131 static int SelfReferences
;
133 static stringList
*GenericNames
;
134 static stringList
*ReferencedTypes
;
139 EKIND_CLASS
, EKIND_FEATURE
, EKIND_LOCAL
, EKIND_QUALIFIED_TAGS
142 static kindOption EiffelKinds
[] = {
143 { TRUE
, 'c', "class", "classes"},
144 { TRUE
, 'f', "feature", "features"},
145 { FALSE
, 'l', "local", "local entities"}
150 static jmp_buf Exception
;
152 static const keywordDesc EiffelKeywordTable
[] = {
153 /* keyword keyword ID */
154 { "alias", KEYWORD_alias
},
155 { "all", KEYWORD_all
},
156 { "and", KEYWORD_and
},
157 { "as", KEYWORD_as
},
158 { "assign", KEYWORD_assign
},
159 { "attached", KEYWORD_attached
},
160 { "check", KEYWORD_check
},
161 { "class", KEYWORD_class
},
162 { "convert", KEYWORD_convert
},
163 { "create", KEYWORD_create
},
164 { "creation", KEYWORD_creation
},
165 { "current", KEYWORD_Current
},
166 { "debug", KEYWORD_debug
},
167 { "deferred", KEYWORD_deferred
},
168 { "detachable", KEYWORD_detachable
},
169 { "do", KEYWORD_do
},
170 { "else", KEYWORD_else
},
171 { "elseif", KEYWORD_elseif
},
172 { "end", KEYWORD_end
},
173 { "ensure", KEYWORD_ensure
},
174 { "expanded", KEYWORD_expanded
},
175 { "export", KEYWORD_export
},
176 { "external", KEYWORD_external
},
177 { "false", KEYWORD_false
},
178 { "feature", KEYWORD_feature
},
179 { "from", KEYWORD_from
},
180 { "frozen", KEYWORD_frozen
},
181 { "if", KEYWORD_if
},
182 { "implies", KEYWORD_implies
},
183 { "indexing", KEYWORD_indexing
},
184 { "infix", KEYWORD_infix
},
185 { "inherit", KEYWORD_inherit
},
186 { "inspect", KEYWORD_inspect
},
187 { "invariant", KEYWORD_invariant
},
188 { "is", KEYWORD_is
},
189 { "like", KEYWORD_like
},
190 { "local", KEYWORD_local
},
191 { "loop", KEYWORD_loop
},
192 { "not", KEYWORD_not
},
193 { "obsolete", KEYWORD_obsolete
},
194 { "old", KEYWORD_old
},
195 { "once", KEYWORD_once
},
196 { "or", KEYWORD_or
},
197 { "prefix", KEYWORD_prefix
},
198 { "redefine", KEYWORD_redefine
},
199 { "rename", KEYWORD_rename
},
200 { "require", KEYWORD_require
},
201 { "rescue", KEYWORD_rescue
},
202 { "result", KEYWORD_Result
},
203 { "retry", KEYWORD_retry
},
204 { "select", KEYWORD_select
},
205 { "separate", KEYWORD_separate
},
206 { "strip", KEYWORD_strip
},
207 { "then", KEYWORD_then
},
208 { "true", KEYWORD_true
},
209 { "undefine", KEYWORD_undefine
},
210 { "unique", KEYWORD_unique
},
211 { "until", KEYWORD_until
},
212 { "variant", KEYWORD_variant
},
213 { "when", KEYWORD_when
},
214 { "xor", KEYWORD_xor
}
218 * FUNCTION DEFINITIONS
221 static void buildEiffelKeywordHash (void)
223 const size_t count
= sizeof (EiffelKeywordTable
) /
224 sizeof (EiffelKeywordTable
[0]);
226 for (i
= 0 ; i
< count
; ++i
)
228 const keywordDesc
* const p
= &EiffelKeywordTable
[i
];
229 addKeyword (p
->name
, Lang_eiffel
, (int) p
->id
);
233 #ifdef TYPE_REFERENCE_TOOL
235 static void addGenericName (tokenInfo
*const token
)
237 vStringUpper (token
->string
);
238 if (vStringLength (token
->string
) > 0)
239 stringListAdd (GenericNames
, vStringNewCopy (token
->string
));
242 static boolean
isGeneric (tokenInfo
*const token
)
244 return (boolean
) stringListHas (GenericNames
, vStringValue (token
->string
));
247 static void reportType (tokenInfo
*const token
)
249 vStringUpper (token
->string
);
250 if (vStringLength (token
->string
) > 0 && ! isGeneric (token
) &&
251 (SelfReferences
|| strcmp (vStringValue (
252 token
->string
), vStringValue (token
->className
)) != 0) &&
253 ! stringListHas (ReferencedTypes
, vStringValue (token
->string
)))
255 printf ("%s\n", vStringValue (token
->string
));
256 stringListAdd (ReferencedTypes
, vStringNewCopy (token
->string
));
260 static int fileGetc (void)
272 if (Debug
> 0 && c
!= EOF
)
277 static int fileUngetc (c
)
279 return ungetc (c
, File
);
282 extern char *readLine (vString
*const vLine
, FILE *const fp
)
290 * Tag generation functions
293 static void makeEiffelClassTag (tokenInfo
*const token
)
295 if (EiffelKinds
[EKIND_CLASS
].enabled
)
297 const char *const name
= vStringValue (token
->string
);
300 initTagEntry (&e
, name
);
302 e
.kindName
= EiffelKinds
[EKIND_CLASS
].name
;
303 e
.kind
= EiffelKinds
[EKIND_CLASS
].letter
;
307 vStringCopy (token
->className
, token
->string
);
310 static void makeEiffelFeatureTag (tokenInfo
*const token
)
312 if (EiffelKinds
[EKIND_FEATURE
].enabled
&&
313 (token
->isExported
|| Option
.include
.fileScope
))
315 const char *const name
= vStringValue (token
->string
);
318 initTagEntry (&e
, name
);
320 e
.isFileScope
= (boolean
) (! token
->isExported
);
321 e
.kindName
= EiffelKinds
[EKIND_FEATURE
].name
;
322 e
.kind
= EiffelKinds
[EKIND_FEATURE
].letter
;
323 e
.extensionFields
.scope
[0] = EiffelKinds
[EKIND_CLASS
].name
;
324 e
.extensionFields
.scope
[1] = vStringValue (token
->className
);
328 if (Option
.include
.qualifiedTags
)
330 vString
* qualified
= vStringNewInit (vStringValue (token
->className
));
331 vStringPut (qualified
, '.');
332 vStringCat (qualified
, token
->string
);
333 e
.name
= vStringValue (qualified
);
335 vStringDelete (qualified
);
338 vStringCopy (token
->featureName
, token
->string
);
341 static void makeEiffelLocalTag (tokenInfo
*const token
)
343 if (EiffelKinds
[EKIND_LOCAL
].enabled
&& Option
.include
.fileScope
)
345 const char *const name
= vStringValue (token
->string
);
346 vString
* scope
= vStringNew ();
349 initTagEntry (&e
, name
);
351 e
.isFileScope
= TRUE
;
352 e
.kindName
= EiffelKinds
[EKIND_LOCAL
].name
;
353 e
.kind
= EiffelKinds
[EKIND_LOCAL
].letter
;
355 vStringCopy (scope
, token
->className
);
356 vStringPut (scope
, '.');
357 vStringCat (scope
, token
->featureName
);
359 e
.extensionFields
.scope
[0] = EiffelKinds
[EKIND_FEATURE
].name
;
360 e
.extensionFields
.scope
[1] = vStringValue (scope
);
363 vStringDelete (scope
);
373 static int skipToCharacter (const int c
)
380 } while (d
!= EOF
&& d
!= c
);
385 /* If a numeric is passed in 'c', this is used as the first digit of the
386 * numeric being parsed.
388 static vString
*parseInteger (int c
)
390 vString
*string
= vStringNew ();
396 vStringPut (string
, c
);
399 else if (! isdigit (c
))
401 while (c
!= EOF
&& (isdigit (c
) || c
== '_'))
403 vStringPut (string
, c
);
406 vStringTerminate (string
);
412 static vString
*parseNumeric (int c
)
414 vString
*string
= vStringNew ();
415 vString
*integer
= parseInteger (c
);
416 vStringCopy (string
, integer
);
417 vStringDelete (integer
);
422 integer
= parseInteger ('\0');
423 vStringPut (string
, c
);
424 vStringCat (string
, integer
);
425 vStringDelete (integer
);
428 if (tolower (c
) == 'e')
430 integer
= parseInteger ('\0');
431 vStringPut (string
, c
);
432 vStringCat (string
, integer
);
433 vStringDelete (integer
);
435 else if (!isspace (c
))
438 vStringTerminate (string
);
443 static int parseEscapedCharacter (void)
450 case 'A': d
= '@'; break;
451 case 'B': d
= '\b'; break;
452 case 'C': d
= '^'; break;
453 case 'D': d
= '$'; break;
454 case 'F': d
= '\f'; break;
455 case 'H': d
= '\\'; break;
456 case 'L': d
= '~'; break;
457 case 'N': d
= '\n'; break;
459 case 'Q': d
= 0x9F; break;
461 case 'Q': d
= '`'; break;
463 case 'R': d
= '\r'; break;
464 case 'S': d
= '#'; break;
465 case 'T': d
= '\t'; break;
466 case 'U': d
= '\0'; break;
467 case 'V': d
= '|'; break;
468 case '%': d
= '%'; break;
469 case '\'': d
= '\''; break;
470 case '"': d
= '"'; break;
471 case '(': d
= '['; break;
472 case ')': d
= ']'; break;
473 case '<': d
= '{'; break;
474 case '>': d
= '}'; break;
476 case '\n': skipToCharacter ('%'); break;
480 vString
*string
= parseInteger ('\0');
481 const char *value
= vStringValue (string
);
482 const unsigned long ascii
= atol (value
);
483 vStringDelete (string
);
486 if (c
== '/' && ascii
< 256)
496 static int parseCharacter (void)
502 result
= parseEscapedCharacter ();
506 skipToCharacter ('\n');
511 static void parseString (vString
*const string
)
513 boolean verbatim
= FALSE
;
514 boolean align
= FALSE
;
516 vString
*verbatimCloser
= vStringNew ();
517 vString
*lastLine
= vStringNew ();
531 end
= (boolean
) (strcmp (vStringValue (lastLine
),
532 vStringValue (verbatimCloser
)) == 0);
537 vStringClear (lastLine
);
538 if (prev
== '[' /* || prev == '{' */)
541 vStringClear (verbatimCloser
);
542 vStringClear (lastLine
);
544 vStringPut (verbatimCloser
, '}');
547 vStringPut (verbatimCloser
, ']');
550 vStringNCat (verbatimCloser
, string
, vStringLength (string
) - 1);
551 vStringClear (string
);
553 if (verbatim
&& align
)
561 c
= parseEscapedCharacter ();
564 vStringPut (string
, c
);
567 vStringPut (lastLine
, c
);
568 vStringTerminate (lastLine
);
573 vStringTerminate (string
);
574 vStringDelete (lastLine
);
575 vStringDelete (verbatimCloser
);
578 /* Read a C identifier beginning with "firstChar" and places it into "name".
580 static void parseIdentifier (vString
*const string
, const int firstChar
)
586 vStringPut (string
, c
);
588 } while (isident (c
));
590 vStringTerminate (string
);
592 fileUngetc (c
); /* unget non-identifier character */
595 static void parseFreeOperator (vString
*const string
, const int firstChar
)
601 vStringPut (string
, c
);
605 vStringTerminate (string
);
607 fileUngetc (c
); /* unget non-identifier character */
610 static void copyToken (tokenInfo
* dst
, const tokenInfo
*src
)
612 dst
->type
= src
->type
;
613 dst
->keyword
= src
->keyword
;
614 dst
->isExported
= src
->isExported
;
616 vStringCopy (dst
->string
, src
->string
);
617 vStringCopy (dst
->className
, src
->className
);
618 vStringCopy (dst
->featureName
, src
->featureName
);
621 static tokenInfo
*newToken (void)
623 tokenInfo
*const token
= xMalloc (1, tokenInfo
);
625 token
->type
= TOKEN_UNDEFINED
;
626 token
->keyword
= KEYWORD_NONE
;
627 token
->isExported
= TRUE
;
629 token
->string
= vStringNew ();
630 token
->className
= vStringNew ();
631 token
->featureName
= vStringNew ();
636 static void deleteToken (tokenInfo
*const token
)
638 vStringDelete (token
->string
);
639 vStringDelete (token
->className
);
640 vStringDelete (token
->featureName
);
645 static void readToken (tokenInfo
*const token
)
649 token
->type
= TOKEN_UNDEFINED
;
650 token
->keyword
= KEYWORD_NONE
;
651 vStringClear (token
->string
);
657 while (c
== '\t' || c
== ' ' || c
== '\n');
661 case EOF
: longjmp (Exception
, (int)ExceptionEOF
); break;
662 case ';': token
->type
= TOKEN_SEMICOLON
; break;
663 case '!': token
->type
= TOKEN_BANG
; break;
664 case '}': token
->type
= TOKEN_CLOSE_BRACE
; break;
665 case ']': token
->type
= TOKEN_CLOSE_BRACKET
; break;
666 case ')': token
->type
= TOKEN_CLOSE_PAREN
; break;
667 case ',': token
->type
= TOKEN_COMMA
; break;
668 case '$': token
->type
= TOKEN_DOLLAR
; break;
669 case '.': token
->type
= TOKEN_DOT
; break;
670 case '{': token
->type
= TOKEN_OPEN_BRACE
; break;
671 case '[': token
->type
= TOKEN_OPEN_BRACKET
; break;
672 case '(': token
->type
= TOKEN_OPEN_PAREN
; break;
673 case '~': token
->type
= TOKEN_TILDE
; break;
679 case '=': token
->type
= TOKEN_OPERATOR
; break;
684 token
->type
= TOKEN_CONSTRAINT
;
685 else if (c
== '-') /* is this the start of a comment? */
687 skipToCharacter ('\n');
694 token
->type
= TOKEN_OPERATOR
;
701 int c2
= fileGetc ();
703 token
->type
= TOKEN_OPERATOR
;
709 token
->type
= TOKEN_COLON
;
711 token
->type
= TOKEN_QUESTION
;
718 if (c
!= '=' && c
!= '>' && !isspace (c
))
720 token
->type
= TOKEN_OPERATOR
;
725 if (c
!= '=' && c
!= '>' && !isspace (c
))
727 token
->type
= TOKEN_OPERATOR
;
732 if (c
!= '/' && c
!= '=' && !isspace (c
))
734 token
->type
= TOKEN_OPERATOR
;
739 if (c
!= '\\' && !isspace (c
))
741 token
->type
= TOKEN_OPERATOR
;
745 token
->type
= TOKEN_STRING
;
746 parseString (token
->string
);
750 token
->type
= TOKEN_CHARACTER
;
757 parseIdentifier (token
->string
, c
);
758 token
->keyword
= analyzeToken (token
->string
, Lang_eiffel
);
759 if (isKeyword (token
, KEYWORD_NONE
))
760 token
->type
= TOKEN_IDENTIFIER
;
762 token
->type
= TOKEN_KEYWORD
;
764 else if (isdigit (c
))
766 vString
* numeric
= parseNumeric (c
);
767 vStringCat (token
->string
, numeric
);
768 vStringDelete (numeric
);
769 token
->type
= TOKEN_NUMERIC
;
771 else if (isFreeOperatorChar (c
))
773 parseFreeOperator (token
->string
, c
);
774 token
->type
= TOKEN_OPERATOR
;
778 token
->type
= TOKEN_UNDEFINED
;
779 Assert (! isType (token
, TOKEN_UNDEFINED
));
789 static boolean
isIdentifierMatch (
790 const tokenInfo
*const token
, const char *const name
)
792 return (boolean
) (isType (token
, TOKEN_IDENTIFIER
) &&
793 strcasecmp (vStringValue (token
->string
), name
) == 0);
796 static void findToken (tokenInfo
*const token
, const tokenType type
)
798 while (! isType (token
, type
))
802 static void findKeyword (tokenInfo
*const token
, const keywordId keyword
)
804 while (! isKeyword (token
, keyword
))
808 static boolean
parseType (tokenInfo
*const token
);
810 static void parseGeneric (tokenInfo
*const token
, boolean declaration __unused__
)
812 unsigned int depth
= 0;
813 #ifdef TYPE_REFERENCE_TOOL
814 boolean constraint
= FALSE
;
816 Assert (isType (token
, TOKEN_OPEN_BRACKET
));
819 if (isType (token
, TOKEN_OPEN_BRACKET
))
824 else if (isType (token
, TOKEN_CLOSE_BRACKET
))
829 #ifdef TYPE_REFERENCE_TOOL
830 else if (declaration
)
832 boolean advanced
= FALSE
;
835 if (isType (token
, TOKEN_CONSTRAINT
))
837 else if (isKeyword (token
, KEYWORD_create
))
838 findKeyword (token
, KEYWORD_end
);
839 else if (isType (token
, TOKEN_IDENTIFIER
))
842 advanced
= parseType (token
);
844 addGenericName (token
);
848 else if (isType (token
, TOKEN_IDENTIFIER
))
849 advanced
= parseType (token
);
859 static boolean
parseType (tokenInfo
*const token
)
861 tokenInfo
* const id
= newToken ();
862 copyToken (id
, token
);
864 if (isType (token
, TOKEN_COLON
)) /* check for "{entity: TYPE}" */
869 if (isKeyword (id
, KEYWORD_like
))
871 if (isType (token
, TOKEN_IDENTIFIER
) ||
872 isKeyword (token
, KEYWORD_Current
))
877 if (isKeyword (id
, KEYWORD_attached
) ||
878 isKeyword (id
, KEYWORD_detachable
) ||
879 isKeyword (id
, KEYWORD_expanded
))
881 copyToken (id
, token
);
884 if (isType (id
, TOKEN_IDENTIFIER
))
886 #ifdef TYPE_REFERENCE_TOOL
889 if (isType (token
, TOKEN_OPEN_BRACKET
))
890 parseGeneric (token
, FALSE
);
891 else if ((strcmp ("BIT", vStringValue (id
->string
)) == 0))
892 readToken (token
); /* read token after number of bits */
899 static void parseEntityType (tokenInfo
*const token
)
901 Assert (isType (token
, TOKEN_COLON
));
904 if (isType (token
, TOKEN_BANG
) || isType (token
, TOKEN_QUESTION
))
905 readToken (token
); /* skip over '!' or '?' */
909 static void parseLocal (tokenInfo
*const token
)
911 Assert (isKeyword (token
, KEYWORD_local
));
914 /* Check keyword first in case local clause is empty
916 while (! isKeyword (token
, KEYWORD_do
) &&
917 ! isKeyword (token
, KEYWORD_once
))
919 #ifndef TYPE_REFERENCE_TOOL
920 if (isType (token
, TOKEN_IDENTIFIER
))
921 makeEiffelLocalTag (token
);
924 if (isType (token
, TOKEN_COLON
))
925 parseEntityType (token
);
929 static void findFeatureEnd (tokenInfo
*const token
)
931 boolean isFound
= isKeyword (token
, KEYWORD_is
);
934 switch (token
->keyword
)
936 case KEYWORD_deferred
:
938 case KEYWORD_external
:
940 case KEYWORD_obsolete
:
942 case KEYWORD_require
:
948 #ifdef TYPE_REFERENCE_TOOL
949 if (isType (token
, TOKEN_OPEN_BRACE
))
952 if (isType (token
, TOKEN_IDENTIFIER
))
955 else if (isType (token
, TOKEN_BANG
))
958 if (isType (token
, TOKEN_IDENTIFIER
))
960 if (isType (token
, TOKEN_BANG
))
965 switch (token
->keyword
)
971 case KEYWORD_inspect
:
992 /* is this a manifest constant? */
993 if (isFound
|| isType (token
, TOKEN_OPERATOR
)) {
994 if (isType (token
, TOKEN_OPERATOR
))
1002 static boolean
readFeatureName (tokenInfo
*const token
)
1004 boolean isFeatureName
= FALSE
;
1006 if (isKeyword (token
, KEYWORD_frozen
))
1008 if (isType (token
, TOKEN_IDENTIFIER
))
1009 isFeatureName
= TRUE
;
1010 else if (isKeyword (token
, KEYWORD_assign
)) /* legacy code */
1011 isFeatureName
= TRUE
;
1012 else if (isKeyword (token
, KEYWORD_infix
) ||
1013 isKeyword (token
, KEYWORD_prefix
))
1016 if (isType (token
, TOKEN_STRING
))
1017 isFeatureName
= TRUE
;
1019 return isFeatureName
;
1022 static void parseArguments (tokenInfo
*const token
)
1024 #ifndef TYPE_REFERENCE_TOOL
1025 findToken (token
, TOKEN_CLOSE_PAREN
);
1028 Assert (isType (token
, TOKEN_OPEN_PAREN
));
1032 if (isType (token
, TOKEN_COLON
))
1033 parseEntityType (token
);
1036 } while (! isType (token
, TOKEN_CLOSE_PAREN
));
1041 static boolean
parseFeature (tokenInfo
*const token
)
1043 boolean found
= FALSE
;
1044 while (readFeatureName (token
))
1047 #ifndef TYPE_REFERENCE_TOOL
1048 makeEiffelFeatureTag (token
);
1051 if (isType (token
, TOKEN_COMMA
))
1056 if (isKeyword (token
, KEYWORD_alias
)) {
1058 #ifndef TYPE_REFERENCE_TOOL
1059 if (isType (token
, TOKEN_STRING
))
1060 makeEiffelFeatureTag (token
);
1064 if (isType (token
, TOKEN_OPEN_PAREN
)) /* arguments? */
1065 parseArguments (token
);
1066 if (isType (token
, TOKEN_COLON
)) /* a query? */
1067 parseEntityType (token
);
1068 if (isKeyword (token
, KEYWORD_assign
))
1073 if (isKeyword (token
, KEYWORD_obsolete
))
1076 if (isType (token
, TOKEN_STRING
))
1079 findFeatureEnd (token
);
1084 static void parseExport (tokenInfo
*const token
)
1086 token
->isExported
= TRUE
;
1088 if (isType (token
, TOKEN_OPEN_BRACE
))
1090 token
->isExported
= FALSE
;
1091 while (! isType (token
, TOKEN_CLOSE_BRACE
))
1093 if (isType (token
, TOKEN_IDENTIFIER
))
1094 token
->isExported
|= !isIdentifierMatch (token
, "NONE");
1101 static void parseFeatureClauses (tokenInfo
*const token
)
1103 Assert (isKeyword (token
, KEYWORD_feature
));
1106 if (isKeyword (token
, KEYWORD_feature
))
1107 parseExport (token
);
1108 if (! isKeyword (token
, KEYWORD_feature
) &&
1109 ! isKeyword (token
, KEYWORD_invariant
) &&
1110 ! isKeyword (token
, KEYWORD_indexing
))
1112 if (! parseFeature (token
))
1115 } while (! isKeyword (token
, KEYWORD_end
) &&
1116 ! isKeyword (token
, KEYWORD_invariant
) &&
1117 ! isKeyword (token
, KEYWORD_indexing
));
1120 static void parseRename (tokenInfo
*const token
)
1122 Assert (isKeyword (token
, KEYWORD_rename
));
1125 if (readFeatureName (token
))
1128 if (isKeyword (token
, KEYWORD_as
))
1131 if (readFeatureName (token
))
1133 #ifndef TYPE_REFERENCE_TOOL
1134 makeEiffelFeatureTag (token
); /* renamed feature */
1140 } while (isType (token
, TOKEN_COMMA
));
1143 static void parseInherit (tokenInfo
*const token
)
1145 Assert (isKeyword (token
, KEYWORD_inherit
));
1147 while (isType (token
, TOKEN_IDENTIFIER
))
1150 if (isType (token
, TOKEN_KEYWORD
))
1152 switch (token
->keyword
) /* check for feature adaptation */
1154 case KEYWORD_rename
:
1155 parseRename (token
);
1156 case KEYWORD_export
:
1157 case KEYWORD_undefine
:
1158 case KEYWORD_redefine
:
1159 case KEYWORD_select
:
1160 findKeyword (token
, KEYWORD_end
);
1171 if (isType (token
, TOKEN_SEMICOLON
))
1176 static void parseConvert (tokenInfo
*const token
)
1178 Assert (isKeyword (token
, KEYWORD_convert
));
1182 if (! isType (token
, TOKEN_IDENTIFIER
))
1184 else if (isType (token
, TOKEN_OPEN_PAREN
))
1186 while (! isType (token
, TOKEN_CLOSE_PAREN
))
1189 else if (isType (token
, TOKEN_COLON
))
1192 if (! isType (token
, TOKEN_OPEN_BRACE
))
1194 else while (! isType (token
, TOKEN_CLOSE_BRACE
))
1197 } while (isType (token
, TOKEN_COMMA
));
1200 static void parseClass (tokenInfo
*const token
)
1202 Assert (isKeyword (token
, KEYWORD_class
));
1204 if (isType (token
, TOKEN_IDENTIFIER
))
1206 #ifndef TYPE_REFERENCE_TOOL
1207 makeEiffelClassTag (token
);
1210 vStringCopy (token
->className
, token
->string
);
1211 vStringUpper (token
->className
);
1213 puts (vStringValue (token
->className
));
1214 if (! PrintReferences
)
1222 if (isType (token
, TOKEN_OPEN_BRACKET
))
1223 parseGeneric (token
, TRUE
);
1224 else if (! isType (token
, TOKEN_KEYWORD
))
1226 else switch (token
->keyword
)
1228 case KEYWORD_inherit
: parseInherit (token
); break;
1229 case KEYWORD_feature
: parseFeatureClauses (token
); break;
1230 case KEYWORD_convert
: parseConvert (token
); break;
1231 default: readToken (token
); break;
1233 } while (! isKeyword (token
, KEYWORD_end
));
1236 static void initialize (const langType language
)
1238 Lang_eiffel
= language
;
1239 buildEiffelKeywordHash ();
1242 static void findEiffelTags (void)
1244 tokenInfo
*const token
= newToken ();
1245 exception_t exception
;
1247 exception
= (exception_t
) (setjmp (Exception
));
1248 while (exception
== ExceptionNone
)
1250 findKeyword (token
, KEYWORD_class
);
1253 deleteToken (token
);
1256 #ifndef TYPE_REFERENCE_TOOL
1258 extern parserDefinition
* EiffelParser (void)
1260 static const char *const extensions
[] = { "e", NULL
};
1261 parserDefinition
* def
= parserNew ("Eiffel");
1262 def
->kinds
= EiffelKinds
;
1263 def
->kindCount
= KIND_COUNT (EiffelKinds
);
1264 def
->extensions
= extensions
;
1265 def
->parser
= findEiffelTags
;
1266 def
->initialize
= initialize
;
1272 static void findReferences (void)
1274 ReferencedTypes
= stringListNew ();
1275 GenericNames
= stringListNew ();
1280 stringListDelete (GenericNames
);
1281 GenericNames
= NULL
;
1282 stringListDelete (ReferencedTypes
);
1283 ReferencedTypes
= NULL
;
1286 static const char *const Usage
=
1287 "Prints names of types referenced by an Eiffel language file.\n"
1289 "Usage: %s [-cdrs] [file_name | -]\n"
1292 " -c Print class name of current file (on first line of output).\n"
1293 " -d Enable debug output.\n"
1294 " -r Print types referenced by current file (default unless -c).\n"
1295 " -s Include self-references.\n"
1298 extern int main (int argc
, char** argv
)
1301 for (i
= 1 ; argv
[i
] != NULL
; ++i
)
1303 const char *const arg
= argv
[i
];
1307 if (arg
[1] == '\0')
1312 else for (j
= 1 ; arg
[j
] != '\0' ; ++j
) switch (arg
[j
])
1314 case 'c': PrintClass
= 1; break;
1315 case 'r': PrintReferences
= 1; break;
1316 case 's': SelfReferences
= 1; break;
1317 case 'd': Debug
= 1; break;
1319 fprintf (errout
, "%s: unknown option: %c\n", argv
[0], arg
[1]);
1320 fprintf (errout
, Usage
, argv
[0]);
1325 else if (File
!= NULL
)
1327 fprintf (errout
, Usage
, argv
[0]);
1333 File
= fopen (FileName
, "r");
1342 PrintReferences
= 1;
1345 fprintf (errout
, Usage
, argv
[0]);
1358 /* vi:set tabstop=4 shiftwidth=4: */