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