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