1 /*
2 * $Id: sml.c 536 2007-06-02 06:09:00Z elliotth $
3 *
4 * Copyright (c) 2002, Venkatesh Prasad Ranganath and 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 SML language files.
10 */
11
12 /*
13 * INCLUDE FILES
14 */
15 #include "general.h" /* must always come first */
16
17 #include <string.h>
18
19 #include "entry.h"
20 #include "parse.h"
21 #include "read.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 } smlKind;
38
39 /*
40 * DATA DEFINITIONS
41 */
42 static kindOption SmlKinds[] = {
43 { TRUE, 'e', "exception", "exception declarations" },
44 { TRUE, 'f', "function", "function definitions" },
45 { TRUE, 'c', "functor", "functor definitions" },
46 { TRUE, 's', "signature", "signature declarations" },
47 { TRUE, 'r', "structure", "structure declarations" },
48 { TRUE, 't', "type", "type definitions" },
49 { TRUE, 'v', "value", "value bindings" }
50 };
51
52 static struct {
53 const char *keyword;
54 smlKind kind;
55 } SmlKeywordTypes [] = {
56 { "abstype", K_TYPE },
57 { "and", K_AND },
58 { "datatype", K_TYPE },
59 { "exception", K_EXCEPTION },
60 { "functor", K_FUNCTOR },
61 { "fun", K_FUNCTION },
62 { "signature", K_SIGNATURE },
63 { "structure", K_STRUCTURE },
64 { "type", K_TYPE },
65 { "val", K_VAL }
66 };
67
68 static unsigned int CommentLevel = 0;
69
70 /*
71 * FUNCTION DEFINITIONS
72 */
73
makeSmlTag(smlKind type,vString * name)74 static void makeSmlTag (smlKind type, vString *name)
75 {
76 tagEntryInfo tag;
77 initTagEntry (&tag, vStringValue (name));
78 tag.kindName = SmlKinds [type].name;
79 tag.kind = SmlKinds [type].letter;
80 makeTagEntry (&tag);
81 }
82
skipSpace(const unsigned char * cp)83 static const unsigned char *skipSpace (const unsigned char *cp)
84 {
85 while (isspace ((int) *cp))
86 ++cp;
87 return cp;
88 }
89
isIdentifier(int c)90 static boolean isIdentifier (int c)
91 {
92 boolean result = FALSE;
93 /* Consider '_' as an delimiter to aid user in tracking it's usage. */
94 const char *const alternateIdentifiers = "!%&$#+-<>=/?@\\~'^|*_";
95 if (isalnum (c))
96 result = TRUE;
97 else if (c != '\0' && strchr (alternateIdentifiers, c) != NULL)
98 result = TRUE;
99 return result;
100 }
101
parseIdentifier(const unsigned char * cp,vString * const identifier)102 static const unsigned char *parseIdentifier (
103 const unsigned char *cp, vString *const identifier)
104 {
105 boolean stringLit = FALSE;
106 vStringClear (identifier);
107 while (*cp != '\0' && (!isIdentifier ((int) *cp) || stringLit))
108 {
109 int oneback = *cp;
110 cp++;
111 if (oneback == '(' && *cp == '*' && stringLit == FALSE)
112 {
113 CommentLevel++;
114 return ++cp;
115 }
116 if (*cp == '"' && oneback != '\\')
117 {
118 stringLit = TRUE;
119 continue;
120 }
121 if (stringLit && *cp == '"' && oneback != '\\')
122 stringLit = FALSE;
123 }
124 if (strcmp ((const char *) cp, "") == 0 || cp == NULL)
125 return cp;
126
127 while (isIdentifier ((int) *cp))
128 {
129 vStringPut (identifier, (int) *cp);
130 cp++;
131 }
132 vStringTerminate (identifier);
133 return cp;
134 }
135
findNextIdentifier(const unsigned char ** cp)136 static smlKind findNextIdentifier (const unsigned char **cp)
137 {
138 smlKind result = K_NONE;
139 vString *const identifier = vStringNew ();
140 unsigned int count = sizeof (SmlKeywordTypes) / sizeof (SmlKeywordTypes [0]);
141 unsigned int i;
142 *cp = parseIdentifier (*cp, identifier);
143 for (i = 0 ; i < count && result == K_NONE ; ++i)
144 {
145 const char *id = vStringValue (identifier);
146 if (strcmp (id, SmlKeywordTypes [i].keyword) == 0)
147 result = SmlKeywordTypes [i].kind;
148 }
149 vStringDelete (identifier);
150 return result;
151 }
152
findSmlTags(void)153 static void findSmlTags (void)
154 {
155 vString *const identifier = vStringNew ();
156 const unsigned char *line;
157 smlKind lastTag = K_NONE;
158
159 while ((line = fileReadLine ()) != NULL)
160 {
161 const unsigned char *cp = skipSpace (line);
162 do
163 {
164 smlKind foundTag;
165 if (CommentLevel != 0)
166 {
167 cp = (const unsigned char *) strstr ((const char *) cp, "*)");
168 if (cp == NULL)
169 continue;
170 else
171 {
172 --CommentLevel;
173 cp += 2;
174 }
175 }
176 foundTag = findNextIdentifier (&cp);
177 if (foundTag != K_NONE)
178 {
179 cp = skipSpace (cp);
180 cp = parseIdentifier (cp, identifier);
181 if (foundTag == K_AND)
182 makeSmlTag (lastTag, identifier);
183 else
184 {
185 makeSmlTag (foundTag, identifier);
186 lastTag = foundTag;
187 }
188 }
189 if (strstr ((const char *) cp, "(*") != NULL)
190 {
191 cp += 2;
192 cp = (const unsigned char *) strstr ((const char *) cp, "*)");
193 if (cp == NULL)
194 ++CommentLevel;
195 }
196 } while (cp != NULL && strcmp ((const char *) cp, "") != 0);
197 }
198 vStringDelete (identifier);
199 }
200
SmlParser(void)201 extern parserDefinition *SmlParser (void)
202 {
203 static const char *const extensions[] = { "sml", "sig", NULL };
204 parserDefinition *def = parserNew ("SML");
205 def->kinds = SmlKinds;
206 def->kindCount = KIND_COUNT (SmlKinds);
207 def->extensions = extensions;
208 def->parser = findSmlTags;
209 return def;
210 }
211
212 /* vi:set tabstop=4 shiftwidth=4: */
213