Make parser includes closer to uctags and sync parser license header
[geany-mirror.git] / ctags / parsers / basic.c
blob0dc2b25fddd4ff06e9c2bee9a2a63ecb7d81baf2
1 /*
2 * Copyright (c) 2000-2006, Darren Hiebert, Elias Pschernig
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.
7 * This module contains functions for generating tags for BlitzBasic
8 * (BlitzMax), PureBasic and FreeBasic language files. For now, this is kept
9 * quite simple - but feel free to ask for more things added any time -
10 * patches are of course most welcome.
14 * INCLUDE FILES
16 #include "general.h" /* must always come first */
18 #include <string.h>
20 #include "parse.h"
21 #include "read.h"
22 #include "routines.h"
23 #include "vstring.h"
26 * DATA DEFINITIONS
28 typedef enum {
29 K_CONST,
30 K_FUNCTION,
31 K_LABEL,
32 K_TYPE,
33 K_VARIABLE,
34 K_ENUM
35 } BasicKind;
37 typedef struct {
38 char const *token;
39 BasicKind kind;
40 } KeyWord;
42 static kindOption BasicKinds[] = {
43 {TRUE, 'c', "constant", "constants"},
44 {TRUE, 'f', "function", "functions"},
45 {TRUE, 'l', "label", "labels"},
46 {TRUE, 't', "type", "types"},
47 {TRUE, 'v', "variable", "variables"},
48 {TRUE, 'g', "enum", "enumerations"}
51 static KeyWord freebasic_keywords[] = {
52 {"dim", K_VARIABLE}, /* must always be the first */
53 {"common", K_VARIABLE}, /* must always be the second */
54 {"const", K_CONST}, /* must always be the third */
55 {"function", K_FUNCTION},
56 {"sub", K_FUNCTION},
57 {"property", K_FUNCTION},
58 {"constructor", K_FUNCTION},
59 {"destructor", K_FUNCTION},
60 {"private sub", K_FUNCTION},
61 {"public sub", K_FUNCTION},
62 {"private function", K_FUNCTION},
63 {"public function", K_FUNCTION},
64 {"type", K_TYPE},
65 {"enum", K_ENUM},
66 {NULL, 0}
70 * FUNCTION DEFINITIONS
73 /* Match the name of a dim or const starting at pos. */
74 static int extract_dim (char const *pos, vString * name, BasicKind kind)
76 const char *old_pos = pos;
77 while (isspace (*pos))
78 pos++;
80 /* create tags only if there is some space between the keyword and the identifier */
81 if (old_pos == pos)
82 return 0;
84 vStringClear (name);
86 if (strncasecmp (pos, "shared", 6) == 0)
87 pos += 6; /* skip keyword "shared" */
89 while (isspace (*pos))
90 pos++;
92 /* capture "dim as String str" */
93 if (strncasecmp (pos, "as", 2) == 0)
95 pos += 2; /* skip keyword "as" */
97 while (isspace (*pos))
98 pos++;
99 while (!isspace (*pos)) /* skip next part which is a type */
100 pos++;
101 while (isspace (*pos))
102 pos++;
103 /* now we are at the name */
105 /* capture "dim as foo ptr bar" */
106 if (strncasecmp (pos, "ptr", 3) == 0 && isspace(*(pos+4)))
108 pos += 3; /* skip keyword "ptr" */
109 while (isspace (*pos))
110 pos++;
112 /* capture "dim as string * 4096 chunk" */
113 if (strncmp (pos, "*", 1) == 0)
115 pos += 1; /* skip "*" */
116 while (isspace (*pos) || isdigit(*pos) || ispunct(*pos))
117 pos++;
120 for (; *pos && !isspace (*pos) && *pos != '(' && *pos != ',' && *pos != '='; pos++)
121 vStringPut (name, *pos);
122 vStringTerminate (name);
123 makeSimpleTag (name, BasicKinds, kind);
125 /* if the line contains a ',', we have multiple declarations */
126 while (*pos && strchr (pos, ','))
128 /* skip all we don't need(e.g. "..., new_array(5), " we skip "(5)") */
129 while (*pos != ',' && *pos != '\'')
130 pos++;
132 if (*pos == '\'')
133 return 0; /* break if we are in a comment */
135 while (isspace (*pos) || *pos == ',')
136 pos++;
138 if (*pos == '\'')
139 return 0; /* break if we are in a comment */
141 vStringClear (name);
142 for (; *pos && !isspace (*pos) && *pos != '(' && *pos != ',' && *pos != '='; pos++)
143 vStringPut (name, *pos);
144 vStringTerminate (name);
145 makeSimpleTag (name, BasicKinds, kind);
148 vStringDelete (name);
149 return 1;
152 /* Match the name of a tag (function, variable, type, ...) starting at pos. */
153 static char const *extract_name (char const *pos, vString * name)
155 while (isspace (*pos))
156 pos++;
157 vStringClear (name);
158 for (; *pos && !isspace (*pos) && *pos != '(' && *pos != ',' && *pos != '='; pos++)
159 vStringPut (name, *pos);
160 vStringTerminate (name);
161 return pos;
164 /* Match a keyword starting at p (case insensitive). */
165 static int match_keyword (const char *p, KeyWord const *kw)
167 vString *name;
168 size_t i;
169 int j;
170 const char *old_p;
171 for (i = 0; i < strlen (kw->token); i++)
173 if (tolower (p[i]) != kw->token[i])
174 return 0;
176 name = vStringNew ();
177 p += i;
178 if (kw == &freebasic_keywords[0] ||
179 kw == &freebasic_keywords[1] ||
180 kw == &freebasic_keywords[2])
181 return extract_dim (p, name, kw->kind); /* extract_dim adds the found tag(s) */
183 old_p = p;
184 while (isspace (*p))
185 p++;
187 /* create tags only if there is some space between the keyword and the identifier */
188 if (old_p == p)
190 vStringDelete (name);
191 return 0;
194 for (j = 0; j < 1; j++)
196 p = extract_name (p, name);
198 makeSimpleTag (name, BasicKinds, kw->kind);
199 vStringDelete (name);
201 return 1;
204 /* Match a "label:" style label. */
205 static void match_colon_label (char const *p)
207 char const *end = p + strlen (p) - 1;
208 while (isspace (*end))
209 end--;
210 if (*end == ':')
212 vString *name = vStringNew ();
213 vStringNCatS (name, p, end - p);
214 makeSimpleTag (name, BasicKinds, K_LABEL);
215 vStringDelete (name);
219 static void findBasicTags (void)
221 const char *line;
222 KeyWord *keywords;
224 keywords = freebasic_keywords;
226 while ((line = (const char *) fileReadLine ()) != NULL)
228 const char *p = line;
229 KeyWord const *kw;
231 while (isspace (*p))
232 p++;
234 /* Empty line or comment? */
235 if (!*p || *p == '\'')
236 continue;
238 /* In Basic, keywords always are at the start of the line. */
239 for (kw = keywords; kw->token; kw++)
240 if (match_keyword (p, kw)) break;
242 /* Is it a label? */
243 match_colon_label (p);
247 parserDefinition *FreeBasicParser (void)
249 static char const *extensions[] = { "bas", "bi", "bb", "pb", NULL };
250 parserDefinition *def = parserNew ("FreeBasic");
251 def->kinds = BasicKinds;
252 def->kindCount = KIND_COUNT (BasicKinds);
253 def->extensions = extensions;
254 def->parser = findBasicTags;
255 return def;
258 /* vi:set tabstop=4 shiftwidth=4: */