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