* src/SDCCasm.[ch]: renamed from asm[ch], use dbuf_getline(), ...
[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
216   dbuf_init (&dbuf, INITIAL_INLINEASM);
217
218   va_start (ap, szFormat);
219   dbuf_tvprintf (&dbuf, szFormat, ap);
220   va_end (ap);
221
222   len = dbuf_get_length (&dbuf);
223   fwrite(dbuf_get_buf (&dbuf), 1, len, fp);
224   dbuf_destroy (&dbuf);
225 }
226
227 void
228 asm_addTree (const ASM_MAPPINGS *pMappings)
229 {
230   const ASM_MAPPING *pMap;
231
232   /* Traverse down first */
233   if (pMappings->pParent)
234     asm_addTree (pMappings->pParent);
235   pMap = pMappings->pMappings;
236   while (pMap->szKey && pMap->szValue) {
237       shash_add (&_h, pMap->szKey, pMap->szValue);
238       pMap++;
239   }
240 }
241
242 /*-----------------------------------------------------------------*/
243 /* printILine - return the readable i-code for this ic             */
244 /*-----------------------------------------------------------------*/
245 const char *
246 printILine (iCode *ic)
247 {
248   char *verbalICode;
249   struct dbuf_s tmpBuf;
250   iCodeTable *icTab = getTableEntry (ic->op);
251
252   dbuf_init (&tmpBuf, 1024);
253
254   if (INLINEASM == ic->op)
255     dbuf_append (&tmpBuf, "inline", (sizeof "inline") - 1);
256   else
257     {
258       /* stuff the temporary file with the readable icode */
259       icTab->iCodePrint (&tmpBuf, ic, icTab->printName);
260     }
261
262   /* null terminate the buffer */
263   dbuf_c_str (&tmpBuf);
264   verbalICode = dbuf_detach (&tmpBuf);
265
266   /* kill the trailing NL */
267   if ('\n' == verbalICode[strlen(verbalICode) - 1])
268     verbalICode[strlen(verbalICode) - 1] = '\0';
269
270   /* and throw it up */
271   return verbalICode;
272 }
273
274
275 /*-----------------------------------------------------------------*/
276 /* skipLine - skip the line from file infp                         */
277 /*-----------------------------------------------------------------*/
278 static int
279 skipLine (FILE *infp)
280 {
281   int c;
282
283   while ((c = getc(infp)) != '\n' && EOF != c)
284     ;
285
286   return EOF != c;
287 }
288
289 /*-----------------------------------------------------------------*/
290 /* printCLine - return the c-code for this lineno                  */
291 /*-----------------------------------------------------------------*/
292 /* int rewinds=0; */
293 const char *
294 printCLine (const char *srcFile, int lineno)
295 {
296   static FILE *inFile = NULL;
297   static struct dbuf_s line;
298   static struct dbuf_s lastSrcFile;
299   static char dbufInitialized = 0;
300   static int inLineNo = 0;
301
302   if (!dbufInitialized)
303     {
304       dbuf_init (&line, 1024);
305       dbuf_init (&lastSrcFile, 1024);
306       dbufInitialized = 1;
307     }
308   else
309     {
310       /* empty the dynamic buffer */
311       dbuf_set_length (&line, 0);
312     }
313
314   if (inFile)
315     {
316       if (strcmp (dbuf_c_str (&lastSrcFile), srcFile) != 0)
317         {
318           fclose (inFile);
319           inFile = NULL;
320           inLineNo = 0;
321           dbuf_set_length (&lastSrcFile, 0);
322           dbuf_append_str (&lastSrcFile, srcFile);
323         }
324       }
325
326   if (!inFile && !(inFile = fopen(srcFile, "r")))
327     {
328       /* can't open the file:
329          don't panic, just return the error message */
330       dbuf_printf(&line, "ERROR: %s", strerror(errno));
331
332       return dbuf_c_str (&line);
333     }
334   else
335     {
336       if (lineno < inLineNo)
337         {
338           /* past the lineno: rewind the file pointer */
339           fseek (inFile, 0, SEEK_SET);
340           inLineNo = 0;
341           /* rewinds++; */
342         }
343
344        /* skip lines until lineno */
345       while (inLineNo + 1 < lineno)
346         {
347           if (!skipLine (inFile))
348             goto err_no_line;
349         }
350
351        /* get the line */
352       if (dbuf_getline (&line, inFile))
353         {
354           inLineNo++;
355           if (inLineNo == lineno)
356             {
357               const char *inLineString = dbuf_c_str (&line);
358               size_t len = strlen (inLineString);
359
360               /* remove the trailing NL */
361               if ('\n' == inLineString[len - 1])
362                 {
363                   dbuf_set_length (&line, len - 1);
364                   inLineString = dbuf_c_str (&line);
365                 }
366
367               /* skip leading spaces */
368               while (isspace (*inLineString))
369                 inLineString++;
370
371               return inLineString;
372             }
373         }
374
375 err_no_line:
376       dbuf_printf(&line, "ERROR: no line number %d in file %s", lineno, srcFile);
377
378       return dbuf_c_str (&line);
379   }
380 }
381
382 static const ASM_MAPPING _asxxxx_mapping[] =
383 {
384   {"labeldef", "%s::"},
385   {"slabeldef", "%s:"},
386   {"tlabeldef", "%05d$:"},
387   {"tlabel", "%05d$"},
388   {"immed", "#"},
389   {"zero", "#0x00"},
390   {"one", "#0x01"},
391   {"area", ".area %s"},
392   {"areacode", ".area %s"},
393   {"areadata", ".area %s"},
394   {"areahome", ".area %s"},
395   {"ascii", ".ascii \"%s\""},
396   {"ds", ".ds %d"},
397   {"db", ".db"},
398   {"dbs", ".db %s"},
399   {"dw", ".dw"},
400   {"dws", ".dw %s"},
401   {"constbyte", "0x%02X"},
402   {"constword", "0x%04X"},
403   {"immedword", "#0x%04X"},
404   {"immedbyte", "#0x%02X"},
405   {"hashedstr", "#%s"},
406   {"lsbimmeds", "#<%s"},
407   {"msbimmeds", "#>%s"},
408   {"module", ".module %s"},
409   {"global", ".globl %s"},
410   {"fileprelude", ""},
411   {"functionheader",
412    "; ---------------------------------\n"
413    "; Function %s\n"
414    "; ---------------------------------"
415   },
416   {"functionlabeldef", "%s:"},
417   {"bankimmeds", "0     ; PENDING: bank support"},
418   {"los","(%s & 0xFF)"},
419   {"his","(%s >> 8)"},
420   {"hihis","(%s >> 16)"},
421   {"hihihis","(%s >> 24)"},
422   {"lod","(%d & 0xFF)"},
423   {"hid","(%d >> 8)"},
424   {"hihid","(%d >> 16)"},
425   {"hihihid","(%d >> 24)"},
426   {"lol","(%05d$ & 0xFF)"},
427   {"hil","(%05d$ >> 8)"},
428   {"hihil","(%05d$ >> 16)"},
429   {"hihihil","(%05d$ >> 24)"},
430   {"equ","="},
431   {"org", ".org 0x%04X"},
432   {NULL, NULL}
433 };
434
435 static const ASM_MAPPING _gas_mapping[] =
436 {
437   {"labeldef", "%s::"},
438   {"slabeldef", "%s:"},
439   {"tlabeldef", "%05d$:"},
440   {"tlabel", "%05d$"},
441   {"immed", "#"},
442   {"zero", "#0x00"},
443   {"one", "#0x01"},
444   {"area", ".section %s"},
445   {"areacode", ".section %s"},
446   {"areadata", ".section %s"},
447   {"areahome", ".section %s"},
448   {"ascii", ".ascii \"%s\""},
449   {"ds", ".ds %d"},
450   {"db", ".db"},
451   {"dbs", ".db %s"},
452   {"dw", ".dw"},
453   {"dws", ".dw %s"},
454   {"constbyte", "0x%02X"},
455   {"constword", "0x%04X"},
456   {"immedword", "#0x%04X"},
457   {"immedbyte", "#0x%02X"},
458   {"hashedstr", "#%s"},
459   {"lsbimmeds", "#<%s"},
460   {"msbimmeds", "#>%s"},
461   {"module", ".file \"%s.c\""},
462   {"global", ".globl %s"},
463   {"extern", ".globl %s"},
464   {"fileprelude", ""},
465   {"functionheader",
466    "; ---------------------------------\n"
467    "; Function %s\n"
468    "; ---------------------------------"
469   },
470   {"functionlabeldef", "%s:"},
471   {"bankimmeds", "0     ; PENDING: bank support"},
472   {NULL, NULL}
473 };
474
475 static const ASM_MAPPING _a390_mapping[] =
476 {
477   {"labeldef", "%s:"},
478   {"slabeldef", "%s:"},
479   {"tlabeldef", "L%05d:"},
480   {"tlabel", "L%05d"},
481   {"immed", "#"},
482   {"zero", "#0"},
483   {"one", "#1"},
484   {"area", "; SECTION NOT SUPPORTED"},
485   {"areacode", "; SECTION NOT SUPPORTED"},
486   {"areadata", "; SECTION NOT SUPPORTED"},
487   {"areahome", "; SECTION NOT SUPPORTED"},
488   {"ascii", "db \"%s\""},
489   {"ds", "; STORAGE NOT SUPPORTED"},
490   {"db", "db"},
491   {"dbs", "db \"%s\""},
492   {"dw", "dw"},
493   {"dws", "dw %s"},
494   {"constbyte", "0%02xh"},
495   {"constword", "0%04xh"},
496   {"immedword", "#0%04Xh"},
497   {"immedbyte", "#0%02Xh"},
498   {"hashedstr", "#%s"},
499   {"lsbimmeds", "#<%s"},
500   {"msbimmeds", "#>%s"},
501   {"module", "; .file \"%s.c\""},
502   {"global", "; .globl %s"},
503   {"fileprelude", ""},
504   {"functionheader",
505    "; ---------------------------------\n"
506    "; Function %s\n"
507    "; ---------------------------------"
508   },
509   {"functionlabeldef", "%s:"},
510   {"bankimmeds", "0     ; PENDING: bank support"},
511   {"los","(%s & 0FFh)"},
512   {"his","((%s / 256) & 0FFh)"},
513   {"hihis","((%s / 65536) & 0FFh)"},
514   {"hihihis","((%s / 16777216) & 0FFh)"},
515   {"lod","(%d & 0FFh)"},
516   {"hid","((%d / 256) & 0FFh)"},
517   {"hihid","((%d / 65536) & 0FFh)"},
518   {"hihihid","((%d / 16777216) & 0FFh)"},
519   {"lol","(L%05d & 0FFh)"},
520   {"hil","((L%05d / 256) & 0FFh)"},
521   {"hihil","((L%05d / 65536) & 0FFh)"},
522   {"hihihil","((L%09d / 16777216) & 0FFh)"},
523   {"equ"," equ"},
524   {"org", ".org 0x%04X"},
525   {NULL, NULL}
526 };
527
528 static const ASM_MAPPING _xa_asm_mapping[] =
529 {
530   {"labeldef", "%s:"},
531   {"slabeldef", "%s:"},
532   {"tlabeldef", "L%05d:"},
533   {"tlabel", "L%05d"},
534   {"immed", "#"},
535   {"zero", "#0"},
536   {"one", "#1"},
537   {"area", ".area %s"},
538   {"areacode", ".area %s"},
539   {"areadata", ".area %s"},
540   {"areahome", ".area %s"},
541   {"ascii", ".db \"%s\""},
542   {"ds", ".ds %d"},
543   {"db", ".db"},
544   {"dbs", ".db \"%s\""},
545   {"dw", ".dw"},
546   {"dws", ".dw %s"},
547   {"constbyte", "0x%02x"},
548   {"constword", "0x%04x"},
549   {"immedword", "0x%04x"},
550   {"immedbyte", "0x%02x"},
551   {"hashedstr", "#%s"},
552   {"lsbimmeds", "#<%s"},
553   {"msbimmeds", "#>%s"},
554   {"module", "; .module %s"},
555   {"global", ".globl %s"},
556   {"fileprelude", ""},
557   {"functionheader",
558    "; ---------------------------------\n"
559    "; Function %s\n"
560    "; ---------------------------------"
561   },
562   {"functionlabeldef", "%s:"},
563   {"bankimmeds", "0     ; PENDING: bank support"},
564   {"los","(%s & 0FFh)"},
565   {"his","((%s / 256) & 0FFh)"},
566   {"hihis","((%s / 65536) & 0FFh)"},
567   {"hihihis","((%s / 16777216) & 0FFh)"},
568   {"lod","(%d & 0FFh)"},
569   {"hid","((%d / 256) & 0FFh)"},
570   {"hihid","((%d / 65536) & 0FFh)"},
571   {"hihihid","((%d / 16777216) & 0FFh)"},
572   {"lol","(L%05d & 0FFh)"},
573   {"hil","((L%05d / 256) & 0FFh)"},
574   {"hihil","((L%05d / 65536) & 0FFh)"},
575   {"hihihil","((L%09d / 16777216) & 0FFh)"},
576   {"equ"," equ"},
577   {NULL, NULL}
578 };
579
580 const ASM_MAPPINGS asm_asxxxx_mapping =
581 {
582   NULL,
583   _asxxxx_mapping
584 };
585
586 const ASM_MAPPINGS asm_gas_mapping =
587 {
588   NULL,
589   _gas_mapping
590 };
591
592 const ASM_MAPPINGS asm_a390_mapping =
593 {
594   NULL,
595   _a390_mapping
596 };
597
598 const ASM_MAPPINGS asm_xa_asm_mapping =
599 {
600   NULL,
601   _xa_asm_mapping
602 };