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