1 /*
2 * $Id: asm.c 536 2007-06-02 06:09:00Z elliotth $
3 *
4 * Copyright (c) 2000-2003, 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 assembly 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 "debug.h"
21 #include "keyword.h"
22 #include "parse.h"
23 #include "read.h"
24 #include "routines.h"
25 #include "vstring.h"
26
27 /*
28 * DATA DECLARATIONS
29 */
30 typedef enum {
31 K_NONE = -1, K_DEFINE, K_LABEL, K_MACRO, K_TYPE
32 } AsmKind;
33
34 typedef enum {
35 OP_UNDEFINED = -1,
36 OP_ALIGN,
37 OP_COLON_EQUAL,
38 OP_END,
39 OP_ENDM,
40 OP_ENDMACRO,
41 OP_ENDP,
42 OP_ENDS,
43 OP_EQU,
44 OP_EQUAL,
45 OP_LABEL,
46 OP_MACRO,
47 OP_PROC,
48 OP_RECORD,
49 OP_SECTIONS,
50 OP_SET,
51 OP_STRUCT,
52 OP_LAST
53 } opKeyword;
54
55 typedef struct {
56 const char *operator;
57 opKeyword keyword;
58 } asmKeyword;
59
60 typedef struct {
61 opKeyword keyword;
62 AsmKind kind;
63 } opKind;
64
65 /*
66 * DATA DEFINITIONS
67 */
68 static langType Lang_asm;
69
70 static kindOption AsmKinds [] = {
71 { TRUE, 'd', "define", "defines" },
72 { TRUE, 'l', "label", "labels" },
73 { TRUE, 'm', "macro", "macros" },
74 { TRUE, 't', "type", "types (structs and records)" }
75 };
76
77 static const asmKeyword AsmKeywords [] = {
78 { "align", OP_ALIGN },
79 { "endmacro", OP_ENDMACRO },
80 { "endm", OP_ENDM },
81 { "end", OP_END },
82 { "endp", OP_ENDP },
83 { "ends", OP_ENDS },
84 { "equ", OP_EQU },
85 { "label", OP_LABEL },
86 { "macro", OP_MACRO },
87 { ":=", OP_COLON_EQUAL },
88 { "=", OP_EQUAL },
89 { "proc", OP_PROC },
90 { "record", OP_RECORD },
91 { "sections", OP_SECTIONS },
92 { "set", OP_SET },
93 { "struct", OP_STRUCT }
94 };
95
96 static const opKind OpKinds [] = {
97 /* must be ordered same as opKeyword enumeration */
98 { OP_ALIGN, K_NONE },
99 { OP_COLON_EQUAL, K_DEFINE },
100 { OP_END, K_NONE },
101 { OP_ENDM, K_NONE },
102 { OP_ENDMACRO, K_NONE },
103 { OP_ENDP, K_NONE },
104 { OP_ENDS, K_NONE },
105 { OP_EQU, K_DEFINE },
106 { OP_EQUAL, K_DEFINE },
107 { OP_LABEL, K_LABEL },
108 { OP_MACRO, K_MACRO },
109 { OP_PROC, K_LABEL },
110 { OP_RECORD, K_TYPE },
111 { OP_SECTIONS, K_NONE },
112 { OP_SET, K_DEFINE },
113 { OP_STRUCT, K_TYPE }
114 };
115
116 /*
117 * FUNCTION DEFINITIONS
118 */
buildAsmKeywordHash(void)119 static void buildAsmKeywordHash (void)
120 {
121 const size_t count = sizeof (AsmKeywords) / sizeof (AsmKeywords [0]);
122 size_t i;
123 for (i = 0 ; i < count ; ++i)
124 {
125 const asmKeyword* const p = AsmKeywords + i;
126 addKeyword (p->operator, Lang_asm, (int) p->keyword);
127 }
128 }
129
analyzeOperator(const vString * const op)130 static opKeyword analyzeOperator (const vString *const op)
131 {
132 vString *keyword = vStringNew ();
133 opKeyword result;
134
135 vStringCopyToLower (keyword, op);
136 result = (opKeyword) lookupKeyword (vStringValue (keyword), Lang_asm);
137 vStringDelete (keyword);
138 return result;
139 }
140
isInitialSymbolCharacter(int c)141 static boolean isInitialSymbolCharacter (int c)
142 {
143 return (boolean) (c != '\0' && (isalpha (c) || strchr ("_$", c) != NULL));
144 }
145
isSymbolCharacter(int c)146 static boolean isSymbolCharacter (int c)
147 {
148 /* '?' character is allowed in AMD 29K family */
149 return (boolean) (c != '\0' && (isalnum (c) || strchr ("_$?", c) != NULL));
150 }
151
readPreProc(const unsigned char * const line)152 static boolean readPreProc (const unsigned char *const line)
153 {
154 boolean result;
155 const unsigned char *cp = line;
156 vString *name = vStringNew ();
157 while (isSymbolCharacter ((int) *cp))
158 {
159 vStringPut (name, *cp);
160 ++cp;
161 }
162 vStringTerminate (name);
163 result = (boolean) (strcmp (vStringValue (name), "define") == 0);
164 if (result)
165 {
166 while (isspace ((int) *cp))
167 ++cp;
168 vStringClear (name);
169 while (isSymbolCharacter ((int) *cp))
170 {
171 vStringPut (name, *cp);
172 ++cp;
173 }
174 vStringTerminate (name);
175 makeSimpleTag (name, AsmKinds, K_DEFINE);
176 }
177 vStringDelete (name);
178 return result;
179 }
180
operatorKind(const vString * const operator,boolean * const found)181 static AsmKind operatorKind (
182 const vString *const operator,
183 boolean *const found)
184 {
185 AsmKind result = K_NONE;
186 const opKeyword kw = analyzeOperator (operator);
187 *found = (boolean) (kw != OP_UNDEFINED);
188 if (*found)
189 {
190 result = OpKinds [kw].kind;
191 Assert (OpKinds [kw].keyword == kw);
192 }
193 return result;
194 }
195
196 /* We must check for "DB", "DB.L", "DCB.W" (68000)
197 */
isDefineOperator(const vString * const operator)198 static boolean isDefineOperator (const vString *const operator)
199 {
200 const unsigned char *const op =
201 (unsigned char*) vStringValue (operator);
202 const size_t length = vStringLength (operator);
203 const boolean result = (boolean) (length > 0 &&
204 toupper ((int) *op) == 'D' &&
205 (length == 2 ||
206 (length == 4 && (int) op [2] == '.') ||
207 (length == 5 && (int) op [3] == '.')));
208 return result;
209 }
210
makeAsmTag(const vString * const name,const vString * const operator,const boolean labelCandidate,const boolean nameFollows)211 static void makeAsmTag (
212 const vString *const name,
213 const vString *const operator,
214 const boolean labelCandidate,
215 const boolean nameFollows)
216 {
217 if (vStringLength (name) > 0)
218 {
219 boolean found;
220 const AsmKind kind = operatorKind (operator, &found);
221 if (found)
222 {
223 if (kind != K_NONE)
224 makeSimpleTag (name, AsmKinds, kind);
225 }
226 else if (isDefineOperator (operator))
227 {
228 if (! nameFollows)
229 makeSimpleTag (name, AsmKinds, K_DEFINE);
230 }
231 else if (labelCandidate)
232 {
233 operatorKind (name, &found);
234 if (! found)
235 makeSimpleTag (name, AsmKinds, K_LABEL);
236 }
237 }
238 }
239
readSymbol(const unsigned char * const start,vString * const sym)240 static const unsigned char *readSymbol (
241 const unsigned char *const start,
242 vString *const sym)
243 {
244 const unsigned char *cp = start;
245 vStringClear (sym);
246 if (isInitialSymbolCharacter ((int) *cp))
247 {
248 while (isSymbolCharacter ((int) *cp))
249 {
250 vStringPut (sym, *cp);
251 ++cp;
252 }
253 vStringTerminate (sym);
254 }
255 return cp;
256 }
257
readOperator(const unsigned char * const start,vString * const operator)258 static const unsigned char *readOperator (
259 const unsigned char *const start,
260 vString *const operator)
261 {
262 const unsigned char *cp = start;
263 vStringClear (operator);
264 while (*cp != '\0' && ! isspace ((int) *cp))
265 {
266 vStringPut (operator, *cp);
267 ++cp;
268 }
269 vStringTerminate (operator);
270 return cp;
271 }
272
findAsmTags(void)273 static void findAsmTags (void)
274 {
275 vString *name = vStringNew ();
276 vString *operator = vStringNew ();
277 const unsigned char *line;
278 boolean inCComment = FALSE;
279
280 while ((line = fileReadLine ()) != NULL)
281 {
282 const unsigned char *cp = line;
283 boolean labelCandidate = (boolean) (! isspace ((int) *cp));
284 boolean nameFollows = FALSE;
285 const boolean isComment = (boolean)
286 (*cp != '\0' && strchr (";*@", *cp) != NULL);
287
288 /* skip comments */
289 if (strncmp ((const char*) cp, "/*", (size_t) 2) == 0)
290 {
291 inCComment = TRUE;
292 cp += 2;
293 }
294 if (inCComment)
295 {
296 do
297 {
298 if (strncmp ((const char*) cp, "*/", (size_t) 2) == 0)
299 {
300 inCComment = FALSE;
301 cp += 2;
302 break;
303 }
304 ++cp;
305 } while (*cp != '\0');
306 }
307 if (isComment || inCComment)
308 continue;
309
310 /* read preprocessor defines */
311 if (*cp == '#')
312 {
313 ++cp;
314 readPreProc (cp);
315 continue;
316 }
317
318 /* skip white space */
319 while (isspace ((int) *cp))
320 ++cp;
321
322 /* read symbol */
323 cp = readSymbol (cp, name);
324 if (vStringLength (name) > 0 && *cp == ':')
325 {
326 labelCandidate = TRUE;
327 ++cp;
328 }
329
330 if (! isspace ((int) *cp) && *cp != '\0')
331 continue;
332
333 /* skip white space */
334 while (isspace ((int) *cp))
335 ++cp;
336
337 /* skip leading dot */
338 #if 0
339 if (*cp == '.')
340 ++cp;
341 #endif
342
343 cp = readOperator (cp, operator);
344
345 /* attempt second read of symbol */
346 if (vStringLength (name) == 0)
347 {
348 while (isspace ((int) *cp))
349 ++cp;
350 cp = readSymbol (cp, name);
351 nameFollows = TRUE;
352 }
353 makeAsmTag (name, operator, labelCandidate, nameFollows);
354 }
355 vStringDelete (name);
356 vStringDelete (operator);
357 }
358
initialize(const langType language)359 static void initialize (const langType language)
360 {
361 Lang_asm = language;
362 buildAsmKeywordHash ();
363 }
364
AsmParser(void)365 extern parserDefinition* AsmParser (void)
366 {
367 static const char *const extensions [] = {
368 "asm", "ASM", "s", "S", NULL
369 };
370 static const char *const patterns [] = {
371 "*.A51",
372 "*.29[kK]",
373 "*.[68][68][kKsSxX]",
374 "*.[xX][68][68]",
375 NULL
376 };
377 parserDefinition* def = parserNew ("Asm");
378 def->kinds = AsmKinds;
379 def->kindCount = KIND_COUNT (AsmKinds);
380 def->extensions = extensions;
381 def->patterns = patterns;
382 def->parser = findAsmTags;
383 def->initialize = initialize;
384 return def;
385 }
386
387 /* vi:set tabstop=4 shiftwidth=4: */
388