1 /*-------------------------------------------------------------------------
2 SDCCasm.c - header file for all types of stuff to support different assemblers.
3
4 Copyright (C) 2000, Michael Hope <michaelh@juju.net.nz>
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 -------------------------------------------------------------------------*/
20
21 /* Provides output functions that modify the output string
22 based on the input tokens and the assembler token mapping
23 specification loaded.
24
25 Note that the functions below only handle digit format modifiers.
26 eg %02X is ok, but %lu and %.4u will fail.
27
28 A 'token' is like !blah or %24f and is under the programmers
29 control. */
30
31 #include <errno.h>
32
33 #include "common.h"
34 #include "dbuf_string.h"
35
36 static hTab *_h;
37
38 const char *
FileBaseName(const char * fileFullName)39 FileBaseName (const char *fileFullName)
40 {
41 const char *p;
42
43 if (!fileFullName)
44 {
45 return "unknown";
46 }
47
48 for (p = fileFullName + strlen (fileFullName) - 1;
49 p >= fileFullName && (*p != '/' && *p != '\\' && *p != ':');
50 --p)
51 ;
52
53 return p + 1;
54 }
55
56 void
dbuf_tvprintf(struct dbuf_s * dbuf,const char * format,va_list ap)57 dbuf_tvprintf (struct dbuf_s *dbuf, const char *format, va_list ap)
58 {
59 /*
60 Under Linux PPC va_list is a structure instead of a primitive type,
61 and doesn't like being passed around. This version turns everything
62 into one function.
63
64 Supports:
65 !tokens
66 %[CIFN] - special formats with no argument (ie list isnt touched)
67 All of the system formats
68
69 This is acheived by expanding the tokens and zero arg formats into
70 one big format string, which is passed to the native printf.
71 */
72 static int count;
73 struct dbuf_s tmpDBuf;
74 const char *noTokens;
75 const char *sz = format;
76 const char *begin = NULL;
77
78 /* First pass: expand all of the macros */
79 dbuf_init (&tmpDBuf, INITIAL_INLINEASM);
80
81 while (*sz)
82 {
83 if (*sz == '!')
84 {
85 /* Start of a token. Search until the first
86 [non alpha, *] and call it a token. */
87 const char *t;
88 struct dbuf_s token;
89
90 if (begin)
91 {
92 /* copy what we have until now */
93 dbuf_append (&tmpDBuf, begin, sz - begin);
94 begin = NULL;
95 }
96
97 dbuf_init (&token, 64);
98 ++sz;
99 while (isalpha ((unsigned char) *sz) || *sz == '*')
100 {
101 dbuf_append (&token, sz++, 1);
102 }
103 /* Now find the token in the token list */
104 if ((t = shash_find (_h, dbuf_c_str (&token))))
105 {
106 dbuf_append_str (&tmpDBuf, t);
107 }
108 else
109 {
110 /* Token not recognized as a valid macro: macro is not expanded */
111 dbuf_append_char (&tmpDBuf, '!');
112 dbuf_append (&tmpDBuf, dbuf_get_buf (&token), dbuf_get_length (&token));
113 }
114 dbuf_destroy (&token);
115 }
116 else
117 {
118 if (!begin)
119 begin = sz;
120 ++sz;
121 }
122 }
123
124 if (begin)
125 {
126 /* copy what we have until now */
127 dbuf_append (&tmpDBuf, begin, sz - begin);
128 begin = NULL;
129 }
130
131 /* Second pass: Expand any macros that we own */
132 sz = noTokens = dbuf_detach_c_str (&tmpDBuf);
133
134 /* recycle tmpDBuf */
135 dbuf_init (&tmpDBuf, INITIAL_INLINEASM);
136
137 while (*sz)
138 {
139 if (*sz == '%')
140 {
141 if (begin)
142 {
143 /* copy what we have until now */
144 dbuf_append (&tmpDBuf, begin, sz - begin);
145 begin = NULL;
146 }
147
148 // See if its one that we handle.
149 ++sz;
150 switch (*sz)
151 {
152 case 'C':
153 // Code segment name.
154 dbuf_append_str (&tmpDBuf, CODE_NAME);
155 ++sz;
156 break;
157
158 case 'F':
159 // Source file name.
160 dbuf_append_str (&tmpDBuf, fullSrcFileName);
161 ++sz;
162 break;
163
164 case 'N':
165 // Current function name.
166 dbuf_append_str (&tmpDBuf, currFunc->rname);
167 ++sz;
168 break;
169
170 case 'I':
171 // Unique ID.
172 dbuf_printf (&tmpDBuf, "%u", ++count);
173 ++sz;
174 break;
175
176 default:
177 // Not one of ours. Copy until the end.
178 dbuf_append_char (&tmpDBuf, '%');
179 while (!isalpha ((unsigned char) *sz))
180 dbuf_append_char (&tmpDBuf, *sz++);
181
182 dbuf_append_char (&tmpDBuf, *sz++);
183 break;
184 }
185 }
186 else
187 {
188 if (!begin)
189 begin = sz;
190 ++sz;
191 }
192 }
193
194 if (begin)
195 {
196 /* copy what we have until now */
197 dbuf_append (&tmpDBuf, begin, sz - begin);
198 begin = NULL;
199 }
200
201 dbuf_free (noTokens);
202
203 dbuf_vprintf (dbuf, dbuf_c_str (&tmpDBuf), ap);
204
205 dbuf_destroy (&tmpDBuf);
206 }
207
208 void
dbuf_tprintf(struct dbuf_s * dbuf,const char * szFormat,...)209 dbuf_tprintf (struct dbuf_s *dbuf, const char *szFormat, ...)
210 {
211 va_list ap;
212 va_start (ap, szFormat);
213 dbuf_tvprintf (dbuf, szFormat, ap);
214 va_end (ap);
215 }
216
217 void
tfprintf(FILE * fp,const char * szFormat,...)218 tfprintf (FILE *fp, const char *szFormat, ...)
219 {
220 va_list ap;
221 struct dbuf_s dbuf;
222
223 dbuf_init (&dbuf, INITIAL_INLINEASM);
224
225 va_start (ap, szFormat);
226 dbuf_tvprintf (&dbuf, szFormat, ap);
227 va_end (ap);
228
229 fwrite (dbuf_get_buf (&dbuf), 1, dbuf_get_length (&dbuf), fp);
230 dbuf_destroy (&dbuf);
231 }
232
233 void
asm_addTree(const ASM_MAPPINGS * pMappings)234 asm_addTree (const ASM_MAPPINGS * pMappings)
235 {
236 const ASM_MAPPING *pMap;
237
238 /* Traverse down first */
239 if (pMappings->pParent)
240 asm_addTree (pMappings->pParent);
241 pMap = pMappings->pMappings;
242 while (pMap->szKey && pMap->szValue)
243 {
244 shash_add (&_h, pMap->szKey, pMap->szValue);
245 pMap++;
246 }
247 }
248
249 /*-----------------------------------------------------------------*/
250 /* printILine - return the readable i-code for this ic */
251 /*-----------------------------------------------------------------*/
252 const char *
printILine(iCode * ic)253 printILine (iCode * ic)
254 {
255 struct dbuf_s tmpBuf;
256 iCodeTable *icTab = getTableEntry (ic->op);
257
258 wassert (icTab);
259
260 dbuf_init (&tmpBuf, 1024);
261
262 if (INLINEASM == ic->op)
263 dbuf_append_str (&tmpBuf, "inline");
264 else
265 {
266 /* stuff the temporary file with the readable icode */
267 icTab->iCodePrint (&tmpBuf, ic, icTab->printName);
268 }
269
270 /* null terminate the buffer */
271 dbuf_chomp (&tmpBuf);
272
273 return dbuf_detach_c_str (&tmpBuf);
274 }
275
276 /*-----------------------------------------------------------------*/
277 /* skipLine - skip the line from file infp */
278 /*-----------------------------------------------------------------*/
279 static int
skipLine(FILE * infp)280 skipLine (FILE * infp)
281 {
282 int c;
283 static char is_eof = 0;
284 size_t len = 0;
285
286 if (is_eof)
287 return 0;
288
289 while ((c = getc (infp)) != '\n' && EOF != c)
290 ++len;
291
292 if (EOF == c)
293 {
294 if (len)
295 {
296 /* EOF in the middle of the line */
297 is_eof = 1;
298 return 1;
299 }
300 else
301 return 0;
302 }
303 else
304 return 1;
305 }
306
307 /*-----------------------------------------------------------------*/
308 /* printCLine - return the c-code for this lineno */
309 /*-----------------------------------------------------------------*/
310 /* int rewinds=0; */
311 const char *
printCLine(const char * srcFile,int lineno)312 printCLine (const char *srcFile, int lineno)
313 {
314 static FILE *inFile = NULL;
315 static struct dbuf_s line;
316 static struct dbuf_s lastSrcFile;
317 static char dbufInitialized = 0;
318 static int inLineNo = 0;
319 size_t len;
320
321 if (!dbufInitialized)
322 {
323 dbuf_init (&line, 1024);
324 dbuf_init (&lastSrcFile, PATH_MAX);
325 dbufInitialized = 1;
326 }
327 else
328 {
329 /* empty the dynamic buffer */
330 dbuf_set_length (&line, 0);
331 }
332
333 if (inFile)
334 {
335 if (strcmp (dbuf_c_str (&lastSrcFile), srcFile) != 0)
336 {
337 fclose (inFile);
338 inFile = NULL;
339 inLineNo = 0;
340 dbuf_set_length (&lastSrcFile, 0);
341 dbuf_append_str (&lastSrcFile, srcFile);
342 }
343 }
344
345 if (!inFile)
346 {
347 if (!(inFile = fopen (srcFile, "r")))
348 {
349 /* can't open the file:
350 don't panic, just return the error message */
351 dbuf_printf (&line, "ERROR: %s", strerror (errno));
352
353 return dbuf_detach_c_str (&line);
354 }
355 else
356 {
357 dbuf_set_length (&lastSrcFile, 0);
358 dbuf_append_str (&lastSrcFile, srcFile);
359 }
360 }
361
362 if (inLineNo > lineno)
363 {
364 /* past the lineno: rewind the file pointer */
365 rewind (inFile);
366 inLineNo = 0;
367 /* rewinds++; */
368 }
369
370 /* skip lines until lineno */
371 while (inLineNo + 1 < lineno)
372 {
373 if (!skipLine (inFile))
374 goto err_no_line;
375 ++inLineNo;
376 }
377
378 /* get the line */
379 if (0 != (len = dbuf_getline (&line, inFile)))
380 {
381 const char *inLineString;
382
383 ++inLineNo;
384
385 /* remove the trailing NL */
386 dbuf_chomp (&line);
387
388 inLineString = dbuf_detach_c_str (&line);
389
390 /* skip leading spaces */
391 while (isspace (*inLineString))
392 ++inLineString;
393
394 return inLineString;
395 }
396
397 err_no_line:
398 dbuf_printf (&line, "ERROR: no line number %d in file %s", lineno, srcFile);
399
400 return dbuf_detach_c_str (&line);
401 }
402
403 static const ASM_MAPPING _asxxxx_mapping[] = {
404 {"labeldef", "%s::"},
405 {"slabeldef", "%s:"},
406 {"tlabeldef", "%05d$:"},
407 {"tlabel", "%05d$"},
408 {"immed", "#"},
409 {"zero", "#0x00"},
410 {"one", "#0x01"},
411 {"area", ".area %s"},
412 {"areacode", ".area %s"},
413 {"areadata", ".area %s"},
414 {"areahome", ".area %s"},
415 {"ascii", ".ascii \"%s\""},
416 {"ds", ".ds %d"},
417 {"db", ".db"},
418 {"dbs", ".db %s"},
419 {"dw", ".dw"},
420 {"dws", ".dw %s"},
421 {"constbyte", "0x%02x"},
422 {"constword", "0x%04x"},
423 {"immedword", "#0x%04x"},
424 {"immedbyte", "#0x%02x"},
425 {"hashedstr", "#%s"},
426 {"lsbimmeds", "#<(%s)"},
427 {"msbimmeds", "#>(%s)"},
428 {"module", ".module %s"},
429 {"global", ".globl %s"},
430 {"fileprelude", ""},
431 {"functionheader",
432 "; ---------------------------------\n"
433 "; Function %s\n"
434 "; ---------------------------------"},
435 {"functionlabeldef", "%s:"},
436 {"globalfunctionlabeldef", "%s::"},
437 {"bankimmeds", "0 ; PENDING: bank support"},
438 {"los", "(%s & 0xFF)"},
439 {"his", "(%s >> 8)"},
440 {"hihis", "(%s >> 16)"},
441 {"hihihis", "(%s >> 24)"},
442 {"lod", "(%d & 0xFF)"},
443 {"hid", "(%d >> 8)"},
444 {"hihid", "(%d >> 16)"},
445 {"hihihid", "(%d >> 24)"},
446 {"lol", "(%05d$ & 0xFF)"},
447 {"hil", "(%05d$ >> 8)"},
448 {"hihil", "(%05d$ >> 16)"},
449 {"hihihil", "(%05d$ >> 24)"},
450 {"equ", "="},
451 {"org", ".org 0x%04X"},
452 {NULL, NULL}
453 };
454
455 static const ASM_MAPPING _asxxxx_smallpdk_mapping[] = {
456 {"labeldef", "%s::"},
457 {"slabeldef", "%s:"},
458 {"tlabeldef", "%05d$:"},
459 {"tlabel", "%05d$"},
460 {"immed", "#"},
461 {"zero", "#0x00"},
462 {"one", "#0x01"},
463 {"area", ".area %s"},
464 {"areacode", ".area %s"},
465 {"areadata", ".area %s"},
466 {"areahome", ".area %s"},
467 {"ascii", ".ascii \"%s\""},
468 {"ds", ".ds %d"},
469 {"db", "ret"},
470 {"dbs", "ret %s"},
471 {"dw", ".dw"},
472 {"dws", ".dw %s"},
473 {"constbyte", "#0x%02x"},
474 {"constword", "0x%04x"},
475 {"immedword", "#0x%04x"},
476 {"immedbyte", "#0x%02x"},
477 {"hashedstr", "#%s"},
478 {"lsbimmeds", "#<(%s)"},
479 {"msbimmeds", "#>(%s)"},
480 {"module", ".module %s"},
481 {"global", ".globl %s"},
482 {"fileprelude", ""},
483 {"functionheader",
484 "; ---------------------------------\n"
485 "; Function %s\n"
486 "; ---------------------------------"},
487 {"functionlabeldef", "%s:"},
488 {"globalfunctionlabeldef", "%s::"},
489 {"bankimmeds", "0 ; PENDING: bank support"},
490 {"los", "(%s & 0xFF)"},
491 {"his", "(%s >> 8)"},
492 {"hihis", "(%s >> 16)"},
493 {"hihihis", "(%s >> 24)"},
494 {"lod", "(%d & 0xFF)"},
495 {"hid", "(%d >> 8)"},
496 {"hihid", "(%d >> 16)"},
497 {"hihihid", "(%d >> 24)"},
498 {"lol", "(%05d$ & 0xFF)"},
499 {"hil", "(%05d$ >> 8)"},
500 {"hihil", "(%05d$ >> 16)"},
501 {"hihihil", "(%05d$ >> 24)"},
502 {"equ", "="},
503 {"org", ".org 0x%04X"},
504 {NULL, NULL}
505 };
506
507 #if 0
508 /* not used */
509 static const ASM_MAPPING _gas_mapping[] = {
510 {"labeldef", "%s::"},
511 {"slabeldef", "%s:"},
512 {"tlabeldef", "%05d$:"},
513 {"tlabel", "%05d$"},
514 {"immed", "#"},
515 {"zero", "#0x00"},
516 {"one", "#0x01"},
517 {"area", ".section %s"},
518 {"areacode", ".section %s"},
519 {"areadata", ".section %s"},
520 {"areahome", ".section %s"},
521 {"ascii", ".ascii \"%s\""},
522 {"ds", ".ds %d"},
523 {"db", ".db"},
524 {"dbs", ".db %s"},
525 {"dw", ".dw"},
526 {"dws", ".dw %s"},
527 {"constbyte", "0x%02X"},
528 {"constword", "0x%04X"},
529 {"immedword", "#0x%04X"},
530 {"immedbyte", "#0x%02X"},
531 {"hashedstr", "#%s"},
532 {"lsbimmeds", "#<%s"},
533 {"msbimmeds", "#>%s"},
534 {"module", ".file \"%s.c\""},
535 {"global", ".globl %s"},
536 {"extern", ".globl %s"},
537 {"fileprelude", ""},
538 {"functionheader",
539 "; ---------------------------------\n"
540 "; Function %s\n"
541 "; ---------------------------------"},
542 {"functionlabeldef", "%s:"},
543 {"globalfunctionlabeldef", "%s::"},
544 {"bankimmeds", "0 ; PENDING: bank support"},
545 {NULL, NULL}
546 };
547 #endif
548
549 static const ASM_MAPPING _a390_mapping[] = {
550 {"labeldef", "%s:"},
551 {"slabeldef", "%s:"},
552 {"tlabeldef", "L%05d:"},
553 {"tlabel", "L%05d"},
554 {"immed", "#"},
555 {"zero", "#0"},
556 {"one", "#1"},
557 {"area", "; SECTION NOT SUPPORTED"},
558 {"areacode", "; SECTION NOT SUPPORTED"},
559 {"areadata", "; SECTION NOT SUPPORTED"},
560 {"areahome", "; SECTION NOT SUPPORTED"},
561 {"ascii", "db \"%s\""},
562 {"ds", "; STORAGE NOT SUPPORTED"},
563 {"db", "db"},
564 {"dbs", "db \"%s\""},
565 {"dw", "dw"},
566 {"dws", "dw %s"},
567 {"constbyte", "0%02xh"},
568 {"constword", "0%04xh"},
569 {"immedword", "#0%04Xh"},
570 {"immedbyte", "#0%02Xh"},
571 {"hashedstr", "#%s"},
572 {"lsbimmeds", "#<%s"},
573 {"msbimmeds", "#>%s"},
574 {"module", "; .file \"%s.c\""},
575 {"global", "; .globl %s"},
576 {"fileprelude", ""},
577 {"functionheader",
578 "; ---------------------------------\n"
579 "; Function %s\n"
580 "; ---------------------------------"},
581 {"functionlabeldef", "%s:"},
582 {"globalfunctionlabeldef", "%s::"},
583 {"bankimmeds", "0 ; PENDING: bank support"},
584 {"los", "(%s & 0FFh)"},
585 {"his", "((%s / 256) & 0FFh)"},
586 {"hihis", "((%s / 65536) & 0FFh)"},
587 {"hihihis", "((%s / 16777216) & 0FFh)"},
588 {"lod", "(%d & 0FFh)"},
589 {"hid", "((%d / 256) & 0FFh)"},
590 {"hihid", "((%d / 65536) & 0FFh)"},
591 {"hihihid", "((%d / 16777216) & 0FFh)"},
592 {"lol", "(L%05d & 0FFh)"},
593 {"hil", "((L%05d / 256) & 0FFh)"},
594 {"hihil", "((L%05d / 65536) & 0FFh)"},
595 {"hihihil", "((L%09d / 16777216) & 0FFh)"},
596 {"equ", " equ"},
597 {"org", ".org 0x%04X"},
598 {NULL, NULL}
599 };
600
601 const ASM_MAPPINGS asm_asxxxx_mapping = {
602 NULL,
603 _asxxxx_mapping
604 };
605
606 const ASM_MAPPINGS asm_asxxxx_smallpdk_mapping = {
607 NULL,
608 _asxxxx_smallpdk_mapping
609 };
610
611 #if 0
612 /* not used */
613 const ASM_MAPPINGS asm_gas_mapping = {
614 NULL,
615 _gas_mapping
616 };
617 #endif
618
619 const ASM_MAPPINGS asm_a390_mapping = {
620 NULL,
621 _a390_mapping
622 };
623
624