1 /*
2 * Copyright (c) 1999-2000, Mjølner Informatics
3 *
4 * Written by Erik Corry <corry@mjolner.dk>
5 *
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License version 2 or (at your option) any later version.
8 *
9 * This module contains functions for generating tags for BETA language
10 * files.
11 */
12
13 /*
14 * INCLUDE FILES
15 */
16 #include "general.h" /* must always come first */
17
18 #include <string.h>
19
20 #include "entry.h"
21 #include "parse.h"
22 #include "read.h"
23 #include "routines.h"
24 #include "vstring.h"
25
26 /*
27 * MACROS
28 */
29 #define isbident(c) (identarray [(unsigned char) (c)])
30
31 /*
32 * DATA DEFINITIONS
33 */
34 typedef enum {
35 K_FRAGMENT, K_PATTERN, K_SLOT, K_VIRTUAL
36 } betaKind;
37
38 static kindDefinition BetaKinds [] = {
39 { true, 'f', "fragment", "fragment definitions"},
40 { false, 'p', "pattern", "all patterns"},
41 { true, 's', "slot", "slots (fragment uses)"},
42 { true, 'v', "virtual", "patterns (virtual or rebound)"}
43 };
44
45 /* [A-Z_a-z0-9] */
46 static const char identarray [256] = {
47 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
48 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32-47 !"#$%&'()*+'-./ */
50 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 0123456789:;<=>? */
51 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 @ABCDEFGHIJKLMNO */
52 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 PQRSTUVWXYZ [\]^_ */
53 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 `abcdefghijklmno */
54 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 pqrstuvwxyz{|}~ */
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128- */
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* -255 */
63
64 /*
65 * FUNCTION DEFINITIONS
66 */
67
makeBetaTag(const char * const name,const betaKind kind)68 static void makeBetaTag (const char* const name, const betaKind kind)
69 {
70 if (BetaKinds [kind].enabled)
71 {
72 tagEntryInfo e;
73 initTagEntry (&e, name, kind);
74 makeTagEntry (&e);
75 }
76 }
77
findBetaTags(void)78 static void findBetaTags (void)
79 {
80 vString *line = vStringNew ();
81 bool incomment = false;
82 bool inquote = false;
83 bool dovirtuals = BetaKinds [K_VIRTUAL].enabled;
84 bool dopatterns = BetaKinds [K_PATTERN].enabled;
85
86 int c;
87 do
88 {
89 bool foundfragmenthere = false;
90 /* find fragment definition (line that starts and ends with --) */
91 int last;
92 int first;
93
94 vStringClear (line);
95
96 while ((c = getcFromInputFile ()) != EOF && c != '\n' && c != '\r')
97 vStringPut (line, c);
98
99 last = vStringLength (line) - 1;
100 first = 0;
101 /* skip white space at start and end of line */
102 while (last > 0 && isspace ((int) vStringChar (line, last))) last--;
103 while (first < last && isspace ((int) vStringChar (line, first))) first++;
104 /* if line still has a reasonable length and ... */
105 if (last - first > 4 &&
106 (vStringChar (line, first) == '-' &&
107 vStringChar (line, first + 1) == '-' &&
108 vStringChar (line, last) == '-' &&
109 vStringChar (line, last - 1) == '-'))
110 {
111 if (!incomment && !inquote)
112 {
113 foundfragmenthere = true;
114 /* skip past -- and whitespace. Also skip back past 'dopart'
115 or 'attributes' to the :. We have to do this because there
116 is no sensible way to include whitespace in a ctags token
117 so the conventional space after the ':' would mess us up */
118 last -= 2;
119 first += 2;
120 while (last && vStringChar (line, last) != ':') last--;
121 while (last && (isspace ((int) vStringChar (line, last-1)))) last--;
122 while (first < last &&
123 (isspace ((int) vStringChar (line, first)) ||
124 vStringChar (line, first) == '-'))
125 first++;
126 /* If there's anything left it is a fragment title */
127 if (first < last - 1)
128 {
129 vStringChar (line, last) = 0;
130 if (strcasecmp ("LIB", vStringValue (line) + first) &&
131 strcasecmp ("PROGRAM", vStringValue (line) + first))
132 {
133 makeBetaTag (vStringValue (line) + first, K_FRAGMENT);
134 }
135 }
136 }
137 } else {
138 int pos = 0;
139 int len = vStringLength (line);
140 if (inquote) goto stringtext;
141 if (incomment) goto commenttext;
142 programtext:
143 for ( ; pos < len; pos++)
144 {
145 if (vStringChar (line, pos) == '\'')
146 {
147 pos++;
148 inquote = true;
149 goto stringtext;
150 }
151 if (vStringChar (line, pos) == '{')
152 {
153 pos++;
154 incomment = true;
155 goto commenttext;
156 }
157 if (vStringChar (line, pos) == '(' && pos < len - 1 &&
158 vStringChar (line, pos+1) == '*')
159 {
160 pos +=2;
161 incomment = true;
162 goto commenttext;
163 }
164 /*
165 * SLOT definition looks like this:
166 * <<SLOT nameofslot: dopart>>
167 * or
168 * <<SLOT nameofslot: descriptor>>
169 */
170 if (!foundfragmenthere &&
171 vStringChar (line, pos) == '<' &&
172 pos+1 < len &&
173 vStringChar (line, pos+1) == '<' &&
174 strstr (vStringValue (line) + pos, ">>"))
175 {
176 /* Found slot name, get start and end */
177 int eoname;
178 char c2;
179 pos += 2; /* skip past << */
180 /* skip past space before SLOT */
181 while (pos < len && isspace ((int) vStringChar (line, pos)))
182 pos++;
183 /* skip past SLOT */
184 if (pos+4 <= len &&
185 !strncasecmp (vStringValue(line) + pos, "SLOT", (size_t)4))
186 pos += 4;
187 /* skip past space after SLOT */
188 while (pos < len && isspace ((int) vStringChar (line, pos)))
189 pos++;
190 eoname = pos;
191 /* skip to end of name */
192 while (eoname < len &&
193 (c2 = vStringChar (line, eoname)) != '>' &&
194 c2 != ':' &&
195 !isspace ((int) c2))
196 eoname++;
197 if (eoname < len)
198 {
199 vStringChar (line, eoname) = 0;
200 if (strcasecmp ("LIB", vStringValue (line) + pos) &&
201 strcasecmp ("PROGRAM", vStringValue (line) + pos) &&
202 strcasecmp ("SLOT", vStringValue (line) + pos))
203 {
204 makeBetaTag (vStringValue (line) + pos, K_SLOT);
205 }
206 }
207 if (eoname+1 < len) {
208 pos = eoname + 1;
209 } else {
210 pos = len;
211 continue;
212 }
213 }
214 /* Only patterns that are virtual, extensions of virtuals or
215 * final bindings are normally included so as not to overload
216 * totally.
217 * That means one of the forms name:: name:< or name::<
218 */
219 if (!foundfragmenthere &&
220 vStringChar (line, pos) == ':' &&
221 (dopatterns ||
222 (dovirtuals &&
223 (vStringChar (line, pos+1) == ':' ||
224 vStringChar (line, pos+1) == '<')
225 )
226 )
227 )
228 {
229 /* Found pattern name, get start and end */
230 int eoname = pos;
231 int soname;
232 while (eoname && isspace ((int) vStringChar (line, eoname-1)))
233 eoname--;
234 foundanothername:
235 /* terminate right after name */
236 vStringChar (line, eoname) = 0;
237 soname = eoname;
238 while (soname &&
239 isbident (vStringChar (line, soname-1)))
240 {
241 soname--;
242 }
243 if (soname != eoname)
244 {
245 makeBetaTag (vStringValue (line) + soname, K_PATTERN);
246 /* scan back past white space */
247 while (soname &&
248 isspace ((int) vStringChar (line, soname-1)))
249 soname--;
250 if (soname && vStringChar (line, soname-1) == ',')
251 {
252 /* we found a new pattern name before comma */
253 eoname = soname;
254 goto foundanothername;
255 }
256 }
257 }
258 }
259 goto endofline;
260 commenttext:
261 for ( ; pos < len; pos++)
262 {
263 if (vStringChar (line, pos) == '*' && pos < len - 1 &&
264 vStringChar (line, pos+1) == ')')
265 {
266 pos += 2;
267 incomment = false;
268 goto programtext;
269 }
270 if (vStringChar (line, pos) == '}')
271 {
272 pos++;
273 incomment = false;
274 goto programtext;
275 }
276 }
277 goto endofline;
278 stringtext:
279 for ( ; pos < len; pos++)
280 {
281 if (vStringChar (line, pos) == '\\')
282 {
283 if (pos < len - 1) pos++;
284 }
285 else if (vStringChar (line, pos) == '\'')
286 {
287 pos++;
288 /* support obsolete '' syntax */
289 if (pos < len && vStringChar (line, pos) == '\'')
290 {
291 continue;
292 }
293 inquote = false;
294 goto programtext;
295 }
296 }
297 }
298 endofline:
299 inquote = false; /* This shouldn't really make a difference */
300 } while (c != EOF);
301 vStringDelete (line);
302 }
303
BetaParser(void)304 extern parserDefinition* BetaParser (void)
305 {
306 static const char *const extensions [] = { "bet", NULL };
307 parserDefinition* def = parserNew ("BETA");
308 def->kindTable = BetaKinds;
309 def->kindCount = ARRAY_SIZE (BetaKinds);
310 def->extensions = extensions;
311 def->parser = findBetaTags;
312 return def;
313 }
314