1 /*
2 * Copyright (c) 2002, Venkatesh Prasad Ranganath and Darren Hiebert
3 *
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
6 *
7 * This module contains functions for generating tags for SML language files.
8 */
9
10 /*
11 * INCLUDE FILES
12 */
13 #include "general.h" /* must always come first */
14
15 #include <string.h>
16
17 #include "debug.h"
18 #include "entry.h"
19 #include "parse.h"
20 #include "read.h"
21 #include "routines.h"
22 #include "vstring.h"
23
24 /*
25 * DATA DECLARATIONS
26 */
27 typedef enum {
28 K_AND = -2,
29 K_NONE = -1,
30 K_EXCEPTION,
31 K_FUNCTION,
32 K_FUNCTOR,
33 K_SIGNATURE,
34 K_STRUCTURE,
35 K_TYPE,
36 K_VAL,
37 K_COUNT /* must be last */
38 } smlKind;
39
40 /*
41 * DATA DEFINITIONS
42 */
43 static kindDefinition SmlKinds[] = {
44 { true, 'e', "exception", "exception declarations" },
45 { true, 'f', "function", "function definitions" },
46 { true, 'c', "functor", "functor definitions" },
47 { true, 's', "signature", "signature declarations" },
48 { true, 'r', "structure", "structure declarations" },
49 { true, 't', "type", "type definitions" },
50 { true, 'v', "value", "value bindings" }
51 };
52
53 static struct {
54 const char *keyword;
55 smlKind kind;
56 } SmlKeywordTypes [] = {
57 { "abstype", K_TYPE },
58 { "and", K_AND },
59 { "datatype", K_TYPE },
60 { "exception", K_EXCEPTION },
61 { "functor", K_FUNCTOR },
62 { "fun", K_FUNCTION },
63 { "signature", K_SIGNATURE },
64 { "structure", K_STRUCTURE },
65 { "type", K_TYPE },
66 { "val", K_VAL }
67 };
68
69 static unsigned int CommentLevel = 0;
70
71 /*
72 * FUNCTION DEFINITIONS
73 */
74
makeSmlTag(smlKind type,vString * name)75 static void makeSmlTag (smlKind type, vString *name)
76 {
77 tagEntryInfo tag;
78
79 Assert (0 <= type && type < K_COUNT);
80 if (! SmlKinds [type].enabled)
81 return;
82
83 initTagEntry (&tag, vStringValue (name), type);
84 makeTagEntry (&tag);
85 }
86
skipSpace(const unsigned char * cp)87 static const unsigned char *skipSpace (const unsigned char *cp)
88 {
89 while (isspace ((int) *cp))
90 ++cp;
91 return cp;
92 }
93
isIdentifier(int c)94 static bool isIdentifier (int c)
95 {
96 bool result = false;
97 /* Consider '_' as an delimiter to aid user in tracking it's usage. */
98 const char *const alternateIdentifiers = "!%&$#+-<>=/?@\\~'^|*_";
99 if (isalnum (c))
100 result = true;
101 else if (c != '\0' && strchr (alternateIdentifiers, c) != NULL)
102 result = true;
103 return result;
104 }
105
parseIdentifier(const unsigned char * cp,vString * const identifier)106 static const unsigned char *parseIdentifier (
107 const unsigned char *cp, vString *const identifier)
108 {
109 bool stringLit = false;
110 vStringClear (identifier);
111 while (*cp != '\0' && (!isIdentifier ((int) *cp) || stringLit))
112 {
113 int oneback = *cp;
114 cp++;
115 if (oneback == '(' && *cp == '*' && stringLit == false)
116 {
117 CommentLevel++;
118 return ++cp;
119 }
120 if (*cp == '"' && oneback != '\\')
121 {
122 stringLit = true;
123 continue;
124 }
125 if (stringLit && *cp == '"' && oneback != '\\')
126 stringLit = false;
127 }
128 if (strcmp ((const char *) cp, "") == 0 || cp == NULL)
129 return cp;
130
131 while (isIdentifier ((int) *cp))
132 {
133 vStringPut (identifier, (int) *cp);
134 cp++;
135 }
136 return cp;
137 }
138
findNextIdentifier(const unsigned char ** cp)139 static smlKind findNextIdentifier (const unsigned char **cp)
140 {
141 smlKind result = K_NONE;
142 vString *const identifier = vStringNew ();
143 unsigned int count = ARRAY_SIZE (SmlKeywordTypes);
144 unsigned int i;
145 *cp = parseIdentifier (*cp, identifier);
146 for (i = 0 ; i < count && result == K_NONE ; ++i)
147 {
148 const char *id = vStringValue (identifier);
149 if (strcmp (id, SmlKeywordTypes [i].keyword) == 0)
150 result = SmlKeywordTypes [i].kind;
151 }
152 vStringDelete (identifier);
153 return result;
154 }
155
findSmlTags(void)156 static void findSmlTags (void)
157 {
158 vString *const identifier = vStringNew ();
159 const unsigned char *line;
160 smlKind lastTag = K_NONE;
161
162 while ((line = readLineFromInputFile ()) != NULL)
163 {
164 const unsigned char *cp = skipSpace (line);
165 do
166 {
167 smlKind foundTag;
168 if (CommentLevel != 0)
169 {
170 cp = (const unsigned char *) strstr ((const char *) cp, "*)");
171 if (cp == NULL)
172 continue;
173 else
174 {
175 --CommentLevel;
176 cp += 2;
177 }
178 }
179 foundTag = findNextIdentifier (&cp);
180 if (foundTag != K_NONE)
181 {
182 cp = skipSpace (cp);
183 cp = parseIdentifier (cp, identifier);
184 if (foundTag == K_AND)
185 {
186 if (lastTag != K_NONE)
187 makeSmlTag (lastTag, identifier);
188 }
189 else
190 {
191 makeSmlTag (foundTag, identifier);
192 lastTag = foundTag;
193 }
194 }
195 if (strstr ((const char *) cp, "(*") != NULL)
196 {
197 cp += 2;
198 cp = (const unsigned char *) strstr ((const char *) cp, "*)");
199 if (cp == NULL)
200 ++CommentLevel;
201 }
202 } while (cp != NULL && strcmp ((const char *) cp, "") != 0);
203 }
204 vStringDelete (identifier);
205 }
206
SmlParser(void)207 extern parserDefinition *SmlParser (void)
208 {
209 static const char *const extensions[] = { "sml", "sig", NULL };
210 parserDefinition *def = parserNew ("SML");
211 def->kindTable = SmlKinds;
212 def->kindCount = ARRAY_SIZE (SmlKinds);
213 def->extensions = extensions;
214 def->parser = findSmlTags;
215 return def;
216 }
217