1 /*
2 *   Copyright (c) 2000-2003, Darren Hiebert
3 *
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.
6 *
7 *   This module contains functions for generating tags for assembly language
8 *   files.
9 */
10 
11 /*
12 *   INCLUDE FILES
13 */
14 #include "general.h"  /* must always come first */
15 
16 #include <string.h>
17 
18 #include "cpreprocessor.h"
19 #include "debug.h"
20 #include "entry.h"
21 #include "keyword.h"
22 #include "parse.h"
23 #include "read.h"
24 #include "routines.h"
25 #include "selectors.h"
26 #include "vstring.h"
27 
28 /*
29 *   DATA DECLARATIONS
30 */
31 typedef enum {
32 	K_PSUEDO_MACRO_END = -2,
33 	K_NONE = -1, K_DEFINE, K_LABEL, K_MACRO, K_TYPE,
34 	K_SECTION,
35 } AsmKind;
36 
37 typedef enum {
38 	OP_UNDEFINED = -1,
39 	OP_ALIGN,
40 	OP_COLON_EQUAL,
41 	OP_END,
42 	OP_ENDM,
43 	OP_ENDMACRO,
44 	OP_ENDP,
45 	OP_ENDS,
46 	OP_EQU,
47 	OP_EQUAL,
48 	OP_LABEL,
49 	OP_MACRO,
50 	OP_PROC,
51 	OP_RECORD,
52 	OP_SECTIONS,
53 	OP_SECTION,
54 	OP_SET,
55 	OP_STRUCT,
56 	OP_LAST
57 } opKeyword;
58 
59 typedef enum {
60 	ASM_SECTION_PLACEMENT,
61 } asmSectionRole;
62 
63 typedef struct {
64 	opKeyword keyword;
65 	AsmKind kind;
66 } opKind;
67 
68 /*
69 *   DATA DEFINITIONS
70 */
71 static langType Lang_asm;
72 
73 static roleDefinition asmSectionRoles [] = {
74 	{ true, "placement", "placement where the assembled code goes" },
75 };
76 
77 static kindDefinition AsmKinds [] = {
78 	{ true, 'd', "define", "defines" },
79 	{ true, 'l', "label",  "labels"  },
80 	{ true, 'm', "macro",  "macros"  },
81 	{ true, 't', "type",   "types (structs and records)"   },
82 	{ true, 's', "section",   "sections",
83 	  .referenceOnly = true, ATTACH_ROLES(asmSectionRoles)},
84 };
85 
86 static const keywordTable AsmKeywords [] = {
87 	{ "align",    OP_ALIGN       },
88 	{ "endmacro", OP_ENDMACRO    },
89 	{ "endm",     OP_ENDM        },
90 	{ "end",      OP_END         },
91 	{ "endp",     OP_ENDP        },
92 	{ "ends",     OP_ENDS        },
93 	{ "equ",      OP_EQU         },
94 	{ "label",    OP_LABEL       },
95 	{ "macro",    OP_MACRO       },
96 	{ ":=",       OP_COLON_EQUAL },
97 	{ "=",        OP_EQUAL       },
98 	{ "proc",     OP_PROC        },
99 	{ "record",   OP_RECORD      },
100 	{ "sections", OP_SECTIONS    },
101 
102 	/* These are used in GNU as. */
103 	{ "section",  OP_SECTION     },
104 	{ "equiv",    OP_EQU         },
105 	{ "eqv",      OP_EQU         },
106 
107 	{ "set",      OP_SET         },
108 	{ "struct",   OP_STRUCT      }
109 };
110 
111 static const opKind OpKinds [] = {
112 	/* must be ordered same as opKeyword enumeration */
113 	{ OP_ALIGN,       K_NONE   },
114 	{ OP_COLON_EQUAL, K_DEFINE },
115 	{ OP_END,         K_NONE   },
116 	{ OP_ENDM,        K_PSUEDO_MACRO_END },
117 	{ OP_ENDMACRO,    K_NONE   },
118 	{ OP_ENDP,        K_NONE   },
119 	{ OP_ENDS,        K_NONE   },
120 	{ OP_EQU,         K_DEFINE },
121 	{ OP_EQUAL,       K_DEFINE },
122 	{ OP_LABEL,       K_LABEL  },
123 	{ OP_MACRO,       K_MACRO  },
124 	{ OP_PROC,        K_LABEL  },
125 	{ OP_RECORD,      K_TYPE   },
126 	{ OP_SECTIONS,    K_NONE   },
127 	{ OP_SECTION,     K_SECTION },
128 	{ OP_SET,         K_DEFINE },
129 	{ OP_STRUCT,      K_TYPE   }
130 };
131 
132 /*
133 *   FUNCTION DEFINITIONS
134 */
analyzeOperator(const vString * const op)135 static opKeyword analyzeOperator (const vString *const op)
136 {
137 	vString *keyword = vStringNew ();
138 	opKeyword result;
139 
140 	vStringCopyToLower (keyword, op);
141 	result = (opKeyword) lookupKeyword (vStringValue (keyword), Lang_asm);
142 	vStringDelete (keyword);
143 	return result;
144 }
145 
isInitialSymbolCharacter(int c)146 static bool isInitialSymbolCharacter (int c)
147 {
148 	return (bool) (c != '\0' && (isalpha (c) || strchr ("_$", c) != NULL));
149 }
150 
isSymbolCharacter(int c)151 static bool isSymbolCharacter (int c)
152 {
153 	/* '?' character is allowed in AMD 29K family */
154 	return (bool) (c != '\0' && (isalnum (c) || strchr ("_$?", c) != NULL));
155 }
156 
operatorKind(const vString * const operator,bool * const found)157 static AsmKind operatorKind (
158 		const vString *const operator,
159 		bool *const found)
160 {
161 	AsmKind result = K_NONE;
162 	const opKeyword kw = analyzeOperator (operator);
163 	*found = (bool) (kw != OP_UNDEFINED);
164 	if (*found)
165 	{
166 		result = OpKinds [kw].kind;
167 		Assert (OpKinds [kw].keyword == kw);
168 	}
169 	return result;
170 }
171 
172 /*  We must check for "DB", "DB.L", "DCB.W" (68000)
173  */
isDefineOperator(const vString * const operator)174 static bool isDefineOperator (const vString *const operator)
175 {
176 	const unsigned char *const op =
177 		(unsigned char*) vStringValue (operator);
178 	const size_t length = vStringLength (operator);
179 	const bool result = (bool) (length > 0  &&
180 		toupper ((int) *op) == 'D'  &&
181 		(length == 2 ||
182 		 (length == 4  &&  (int) op [2] == '.') ||
183 		 (length == 5  &&  (int) op [3] == '.')));
184 	return result;
185 }
186 
makeAsmTag(const vString * const name,const vString * const operator,const bool labelCandidate,const bool nameFollows,const bool directive,int * lastMacroCorkIndex)187 static void makeAsmTag (
188 		const vString *const name,
189 		const vString *const operator,
190 		const bool labelCandidate,
191 		const bool nameFollows,
192 		const bool directive,
193 		int *lastMacroCorkIndex)
194 {
195 	if (vStringLength (name) > 0)
196 	{
197 		bool found;
198 		const AsmKind kind = operatorKind (operator, &found);
199 		if (found)
200 		{
201 			if (kind > K_NONE)
202 				makeSimpleTag (name, kind);
203 		}
204 		else if (isDefineOperator (operator))
205 		{
206 			if (! nameFollows)
207 				makeSimpleTag (name, K_DEFINE);
208 		}
209 		else if (labelCandidate)
210 		{
211 			operatorKind (name, &found);
212 			if (! found)
213 				makeSimpleTag (name, K_LABEL);
214 		}
215 		else if (directive)
216 		{
217 			bool found_dummy;
218 			const AsmKind kind_for_directive = operatorKind (name, &found_dummy);
219 			tagEntryInfo *macro_tag;
220 
221 			switch (kind_for_directive)
222 			{
223 			case K_NONE:
224 				break;
225 			case K_MACRO:
226 				*lastMacroCorkIndex = makeSimpleTag (operator,
227 													 kind_for_directive);
228 				if (*lastMacroCorkIndex != CORK_NIL)
229 					registerEntry (*lastMacroCorkIndex);
230 				break;
231 			case K_PSUEDO_MACRO_END:
232 				macro_tag = getEntryInCorkQueue (*lastMacroCorkIndex);
233 				if (macro_tag)
234 					macro_tag->extensionFields.endLine = getInputLineNumber ();
235 				*lastMacroCorkIndex = CORK_NIL;
236 				break;
237 			case K_SECTION:
238 				makeSimpleRefTag (operator,
239 								  kind_for_directive,
240 								  ASM_SECTION_PLACEMENT);
241 				break;
242 			default:
243 				makeSimpleTag (operator, kind_for_directive);
244 			}
245 		}
246 	}
247 }
248 
readSymbol(const unsigned char * const start,vString * const sym)249 static const unsigned char *readSymbol (
250 		const unsigned char *const start,
251 		vString *const sym)
252 {
253 	const unsigned char *cp = start;
254 	vStringClear (sym);
255 	if (isInitialSymbolCharacter ((int) *cp))
256 	{
257 		while (isSymbolCharacter ((int) *cp))
258 		{
259 			vStringPut (sym, *cp);
260 			++cp;
261 		}
262 	}
263 	return cp;
264 }
265 
readOperator(const unsigned char * const start,vString * const operator)266 static const unsigned char *readOperator (
267 		const unsigned char *const start,
268 		vString *const operator)
269 {
270 	const unsigned char *cp = start;
271 	vStringClear (operator);
272 	while (*cp != '\0'  &&  ! isspace ((int) *cp) && *cp != ',')
273 	{
274 		vStringPut (operator, *cp);
275 		++cp;
276 	}
277 	return cp;
278 }
279 
asmReadLineFromInputFile(void)280 static const unsigned char *asmReadLineFromInputFile (void)
281 {
282 	static vString *line;
283 	int c;
284 
285 	line = vStringNewOrClear (line);
286 
287 	while ((c = cppGetc()) != EOF)
288 	{
289 		if (c == '\n')
290 			break;
291 		else if (c == STRING_SYMBOL || c == CHAR_SYMBOL)
292 		{
293 			/* We cannot store these values to vString
294 			 * Store a whitespace as a dummy value for them.
295 			 */
296 			vStringPut (line, ' ');
297 		}
298 		else
299 			vStringPut (line, c);
300 	}
301 
302 	if ((vStringLength (line) == 0)&& (c == EOF))
303 		return NULL;
304 	else
305 		return (unsigned char *)vStringValue (line);
306 }
307 
findAsmTags(void)308 static void findAsmTags (void)
309 {
310 	vString *name = vStringNew ();
311 	vString *operator = vStringNew ();
312 	const unsigned char *line;
313 
314 	cppInit (false, false, false, false,
315 			 KIND_GHOST_INDEX, 0, 0, KIND_GHOST_INDEX, KIND_GHOST_INDEX, 0, 0,
316 			 FIELD_UNKNOWN);
317 
318 	 int lastMacroCorkIndex = CORK_NIL;
319 
320 	while ((line = asmReadLineFromInputFile ()) != NULL)
321 	{
322 		const unsigned char *cp = line;
323 		bool labelCandidate = (bool) (! isspace ((int) *cp));
324 		bool nameFollows = false;
325 		bool directive = false;
326 		const bool isComment = (bool)
327 				(*cp != '\0' && strchr (";*@", *cp) != NULL);
328 
329 		/* skip comments */
330 		if (isComment)
331 			continue;
332 
333 		/* skip white space */
334 		while (isspace ((int) *cp))
335 			++cp;
336 
337 		/* read symbol */
338 		if (*cp == '.')
339 		{
340 			directive = true;
341 			labelCandidate = false;
342 			++cp;
343 		}
344 
345 		cp = readSymbol (cp, name);
346 		if (vStringLength (name) > 0)
347 		{
348 			if (*cp == ':')
349 			{
350 				labelCandidate = true;
351 				++cp;
352 			}
353 			else if (anyKindEntryInScope (CORK_NIL,
354 										  vStringValue (name),
355 										  K_MACRO))
356 				labelCandidate = false;
357 		}
358 
359 		if (! isspace ((int) *cp)  &&  *cp != '\0')
360 			continue;
361 
362 		/* skip white space */
363 		while (isspace ((int) *cp))
364 			++cp;
365 
366 		/* skip leading dot */
367 #if 0
368 		if (*cp == '.')
369 			++cp;
370 #endif
371 
372 		cp = readOperator (cp, operator);
373 
374 		/* attempt second read of symbol */
375 		if (vStringLength (name) == 0)
376 		{
377 			while (isspace ((int) *cp))
378 				++cp;
379 			cp = readSymbol (cp, name);
380 			nameFollows = true;
381 		}
382 		makeAsmTag (name, operator, labelCandidate, nameFollows, directive,
383 					&lastMacroCorkIndex);
384 	}
385 
386 	cppTerminate ();
387 
388 	vStringDelete (name);
389 	vStringDelete (operator);
390 }
391 
initialize(const langType language)392 static void initialize (const langType language)
393 {
394 	Lang_asm = language;
395 }
396 
AsmParser(void)397 extern parserDefinition* AsmParser (void)
398 {
399 	static const char *const extensions [] = {
400 		"asm", "ASM", "s", "S", NULL
401 	};
402 	static const char *const patterns [] = {
403 		"*.A51",
404 		"*.29[kK]",
405 		"*.[68][68][kKsSxX]",
406 		"*.[xX][68][68]",
407 		NULL
408 	};
409 	static selectLanguage selectors[] = { selectByArrowOfR,
410 					      NULL };
411 
412 	parserDefinition* def = parserNew ("Asm");
413 	def->kindTable      = AsmKinds;
414 	def->kindCount  = ARRAY_SIZE (AsmKinds);
415 	def->extensions = extensions;
416 	def->patterns   = patterns;
417 	def->parser     = findAsmTags;
418 	def->initialize = initialize;
419 	def->keywordTable = AsmKeywords;
420 	def->keywordCount = ARRAY_SIZE (AsmKeywords);
421 	def->selectLanguage = selectors;
422 	def->useCork = CORK_QUEUE | CORK_SYMTAB;
423 	return def;
424 }
425