Remove duplicate NEWS item
[geany-mirror.git] / tagmanager / asm.c
blob6dc7adc426f707bac330f876fbcb852a81116dc8
1 /*
2 * Copyright (c) 2000-2003, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License.
7 * This module contains functions for generating tags for assembly language
8 * files.
9 */
12 * INCLUDE FILES
14 #include "general.h" /* must always come first */
16 #include <string.h>
18 #include "keyword.h"
19 #include "parse.h"
20 #include "read.h"
21 #include "main.h"
22 #include "vstring.h"
25 * DATA DECLARATIONS
27 typedef enum {
28 K_NONE = -1, K_DEFINE, K_LABEL, K_MACRO, K_TYPE
29 } AsmKind;
31 typedef enum {
32 OP_UNDEFINED = -1,
33 OP_ALIGN,
34 OP_COLON_EQUAL,
35 OP_END,
36 OP_ENDM,
37 OP_ENDMACRO,
38 OP_ENDP,
39 OP_ENDS,
40 OP_EQU,
41 OP_EQUAL,
42 OP_LABEL,
43 OP_MACRO,
44 OP_PROC,
45 OP_RECORD,
46 OP_SECTIONS,
47 OP_SET,
48 OP_STRUCT,
49 OP_LAST
50 } opKeyword;
52 typedef struct {
53 const char *operator;
54 opKeyword keyword;
55 } asmKeyword;
57 typedef struct {
58 opKeyword keyword;
59 AsmKind kind;
60 } opKind;
63 * DATA DEFINITIONS
65 static langType Lang_asm;
67 static kindOption AsmKinds [] = {
68 { TRUE, 'd', "macro", "defines" },
69 { TRUE, 'l', "namespace", "labels" },
70 { TRUE, 'm', "function", "macros" },
71 { TRUE, 't', "struct", "types (structs and records)" }
74 static const asmKeyword AsmKeywords [] = {
75 { "align", OP_ALIGN },
76 { "endmacro", OP_ENDMACRO },
77 { "endm", OP_ENDM },
78 { "end", OP_END },
79 { "endp", OP_ENDP },
80 { "ends", OP_ENDS },
81 { "equ", OP_EQU },
82 { "label", OP_LABEL },
83 { "macro", OP_MACRO },
84 { ":=", OP_COLON_EQUAL },
85 { "=", OP_EQUAL },
86 { "proc", OP_PROC },
87 { "record", OP_RECORD },
88 { "sections", OP_SECTIONS },
89 { "set", OP_SET },
90 { "struct", OP_STRUCT }
93 static const opKind OpKinds [] = {
94 /* must be ordered same as opKeyword enumeration */
95 { OP_ALIGN, K_NONE },
96 { OP_COLON_EQUAL, K_DEFINE },
97 { OP_END, K_NONE },
98 { OP_ENDM, K_NONE },
99 { OP_ENDMACRO, K_NONE },
100 { OP_ENDP, K_NONE },
101 { OP_ENDS, K_NONE },
102 { OP_EQU, K_DEFINE },
103 { OP_EQUAL, K_DEFINE },
104 { OP_LABEL, K_LABEL },
105 { OP_MACRO, K_MACRO },
106 { OP_PROC, K_LABEL },
107 { OP_RECORD, K_TYPE },
108 { OP_SECTIONS, K_NONE },
109 { OP_SET, K_DEFINE },
110 { OP_STRUCT, K_TYPE }
114 * FUNCTION DEFINITIONS
116 static void buildAsmKeywordHash (void)
118 const size_t count = sizeof (AsmKeywords) / sizeof (AsmKeywords [0]);
119 size_t i;
120 for (i = 0 ; i < count ; ++i)
122 const asmKeyword* const p = AsmKeywords + i;
123 addKeyword (p->operator, Lang_asm, (int) p->keyword);
127 static opKeyword analyzeOperator (const vString *const op)
129 vString *keyword = vStringNew ();
130 opKeyword result;
132 vStringCopyToLower (keyword, op);
133 result = (opKeyword) lookupKeyword (vStringValue (keyword), Lang_asm);
134 vStringDelete (keyword);
135 return result;
138 static boolean isInitialSymbolCharacter (int c)
140 return (boolean) (c != '\0' && (isalpha (c) || strchr ("_$", c) != NULL));
143 static boolean isSymbolCharacter (int c)
145 /* '?' character is allowed in AMD 29K family */
146 return (boolean) (c != '\0' && (isalnum (c) || strchr ("_$?", c) != NULL));
149 static boolean readPreProc (const unsigned char *const line)
151 boolean result;
152 const unsigned char *cp = line;
153 vString *name = vStringNew ();
154 while (isSymbolCharacter ((int) *cp))
156 vStringPut (name, *cp);
157 ++cp;
159 vStringTerminate (name);
160 result = (boolean) (strcmp (vStringValue (name), "define") == 0);
161 if (result)
163 while (isspace ((int) *cp))
164 ++cp;
165 vStringClear (name);
166 while (isSymbolCharacter ((int) *cp))
168 vStringPut (name, *cp);
169 ++cp;
171 vStringTerminate (name);
172 makeSimpleTag (name, AsmKinds, K_DEFINE);
174 vStringDelete (name);
175 return result;
178 static AsmKind operatorKind (
179 const vString *const operator,
180 boolean *const found)
182 AsmKind result = K_NONE;
183 const opKeyword kw = analyzeOperator (operator);
184 *found = (boolean) (kw != OP_UNDEFINED);
185 if (*found)
187 result = OpKinds [kw].kind;
188 Assert (OpKinds [kw].keyword == kw);
190 return result;
193 /* We must check for "DB", "DB.L", "DCB.W" (68000)
195 static boolean isDefineOperator (const vString *const operator)
197 const unsigned char *const op =
198 (unsigned char*) vStringValue (operator);
199 const size_t length = vStringLength (operator);
200 const boolean result = (boolean) (length > 0 &&
201 toupper ((int) *op) == 'D' &&
202 (length == 2 ||
203 (length == 4 && (int) op [2] == '.') ||
204 (length == 5 && (int) op [3] == '.')));
205 return result;
208 static void makeAsmTag (
209 const vString *const name,
210 const vString *const operator,
211 const boolean labelCandidate,
212 const boolean nameFollows)
214 if (vStringLength (name) > 0)
216 boolean found;
217 const AsmKind kind = operatorKind (operator, &found);
218 if (found)
220 if (kind != K_NONE)
221 makeSimpleTag (name, AsmKinds, kind);
223 else if (isDefineOperator (operator))
225 if (! nameFollows)
226 makeSimpleTag (name, AsmKinds, K_DEFINE);
228 else if (labelCandidate)
230 operatorKind (name, &found);
231 if (! found)
232 makeSimpleTag (name, AsmKinds, K_LABEL);
237 static const unsigned char *readSymbol (
238 const unsigned char *const start,
239 vString *const sym)
241 const unsigned char *cp = start;
242 vStringClear (sym);
243 if (isInitialSymbolCharacter ((int) *cp))
245 while (isSymbolCharacter ((int) *cp))
247 vStringPut (sym, *cp);
248 ++cp;
250 vStringTerminate (sym);
252 return cp;
255 static const unsigned char *readOperator (
256 const unsigned char *const start,
257 vString *const operator)
259 const unsigned char *cp = start;
260 vStringClear (operator);
261 while (*cp != '\0' && ! isspace ((int) *cp))
263 vStringPut (operator, *cp);
264 ++cp;
266 vStringTerminate (operator);
267 return cp;
270 static void findAsmTags (void)
272 vString *name = vStringNew ();
273 vString *operator = vStringNew ();
274 const unsigned char *line;
275 boolean inCComment = FALSE;
277 while ((line = fileReadLine ()) != NULL)
279 const unsigned char *cp = line;
280 boolean labelCandidate = (boolean) (! isspace ((int) *cp));
281 boolean nameFollows = FALSE;
282 const boolean isComment = (boolean)
283 (*cp != '\0' && strchr (";*@", *cp) != NULL);
285 /* skip comments */
286 if (strncmp ((const char*) cp, "/*", (size_t) 2) == 0)
288 inCComment = TRUE;
289 cp += 2;
291 if (inCComment)
295 if (strncmp ((const char*) cp, "*/", (size_t) 2) == 0)
297 inCComment = FALSE;
298 cp += 2;
299 break;
301 ++cp;
302 } while (*cp != '\0');
304 if (isComment || inCComment)
305 continue;
307 /* read preprocessor defines */
308 if (*cp == '#')
310 ++cp;
311 readPreProc (cp);
312 continue;
315 /* skip white space */
316 while (isspace ((int) *cp))
317 ++cp;
319 /* read symbol */
320 cp = readSymbol (cp, name);
321 if (vStringLength (name) > 0 && *cp == ':')
323 labelCandidate = TRUE;
324 ++cp;
327 if (! isspace ((int) *cp) && *cp != '\0')
328 continue;
330 /* skip white space */
331 while (isspace ((int) *cp))
332 ++cp;
334 /* skip leading dot */
335 #if 0
336 if (*cp == '.')
337 ++cp;
338 #endif
340 cp = readOperator (cp, operator);
342 /* attempt second read of symbol */
343 if (vStringLength (name) == 0)
345 while (isspace ((int) *cp))
346 ++cp;
347 cp = readSymbol (cp, name);
348 nameFollows = TRUE;
350 makeAsmTag (name, operator, labelCandidate, nameFollows);
352 vStringDelete (name);
353 vStringDelete (operator);
356 static void initialize (const langType language)
358 Lang_asm = language;
359 buildAsmKeywordHash ();
362 extern parserDefinition* AsmParser (void)
364 static const char *const extensions [] = {
365 "asm", "ASM", "s", "S", NULL
367 static const char *const patterns [] = {
368 "*.A51",
369 "*.29[kK]",
370 "*.[68][68][kKsSxX]",
371 "*.[xX][68][68]",
372 NULL
374 parserDefinition* def = parserNew ("Asm");
375 def->kinds = AsmKinds;
376 def->kindCount = KIND_COUNT (AsmKinds);
377 def->extensions = extensions;
378 def->patterns = patterns;
379 def->parser = findAsmTags;
380 def->initialize = initialize;
381 return def;
384 /* vi:set tabstop=4 shiftwidth=4: */