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