fixed skipLine() and printCLine()
[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   static char is_eof = 0;
283   size_t len = 0;
284
285   if (is_eof)
286     return 0;
287
288   while ((c = getc(infp)) != '\n' && EOF != c)
289     ++len;
290
291   if (EOF == c)
292     {
293       if (len)
294         {
295           /* EOF in the middle of the line */
296           is_eof = 1;
297           return 1;
298         }  
299       else
300         return 0;
301     }
302   else
303     return 1;
304 }
305
306 /*-----------------------------------------------------------------*/
307 /* printCLine - return the c-code for this lineno                  */
308 /*-----------------------------------------------------------------*/
309 /* int rewinds=0; */
310 const char *
311 printCLine (const char *srcFile, int lineno)
312 {
313   static FILE *inFile = NULL;
314   static struct dbuf_s line;
315   static struct dbuf_s lastSrcFile;
316   static char dbufInitialized = 0;
317   static int inLineNo = 0;
318
319   if (!dbufInitialized)
320     {
321       dbuf_init (&line, 1024);
322       dbuf_init (&lastSrcFile, PATH_MAX);
323       dbufInitialized = 1;
324     }
325   else
326     {
327       /* empty the dynamic buffer */
328       dbuf_set_length (&line, 0);
329     }
330
331   if (inFile)
332     {
333       if (strcmp (dbuf_c_str (&lastSrcFile), srcFile) != 0)
334         {
335           fclose (inFile);
336           inFile = NULL;
337           inLineNo = 0;
338           dbuf_set_length (&lastSrcFile, 0);
339           dbuf_append_str (&lastSrcFile, srcFile);
340         }
341     }
342
343   if (!inFile)
344     {
345       if (!(inFile = fopen(srcFile, "r")))
346         {
347           /* can't open the file:
348              don't panic, just return the error message */
349           dbuf_printf(&line, "ERROR: %s", strerror(errno));
350
351           return dbuf_c_str (&line);
352         }
353       else
354         {
355           dbuf_set_length (&lastSrcFile, 0);
356           dbuf_append_str (&lastSrcFile, srcFile);
357         }
358     }
359
360   if (inLineNo > lineno)
361     {
362       /* past the lineno: rewind the file pointer */
363       rewind (inFile);
364       inLineNo = 0;
365       /* rewinds++; */
366     }
367
368    /* skip lines until lineno */
369   while (inLineNo + 1 < lineno)
370     {
371       if (!skipLine (inFile))
372         goto err_no_line;
373       ++inLineNo;
374     }
375
376    /* get the line */
377   if (dbuf_getline (&line, inFile))
378     {
379       const char *inLineString = dbuf_c_str (&line);
380       size_t len = strlen (inLineString);
381
382       ++inLineNo;
383
384       /* remove the trailing NL */
385       if ('\n' == inLineString[len - 1])
386         {
387           dbuf_set_length (&line, len - 1);
388           inLineString = dbuf_c_str (&line);
389         }
390
391       /* skip leading spaces */
392       while (isspace (*inLineString))
393         inLineString++;
394
395       return inLineString;
396     }
397
398 err_no_line:
399   dbuf_printf(&line, "ERROR: no line number %d in file %s", lineno, srcFile);
400
401   return dbuf_c_str (&line);
402 }
403
404 static const ASM_MAPPING _asxxxx_mapping[] =
405 {
406   {"labeldef", "%s::"},
407   {"slabeldef", "%s:"},
408   {"tlabeldef", "%05d$:"},
409   {"tlabel", "%05d$"},
410   {"immed", "#"},
411   {"zero", "#0x00"},
412   {"one", "#0x01"},
413   {"area", ".area %s"},
414   {"areacode", ".area %s"},
415   {"areadata", ".area %s"},
416   {"areahome", ".area %s"},
417   {"ascii", ".ascii \"%s\""},
418   {"ds", ".ds %d"},
419   {"db", ".db"},
420   {"dbs", ".db %s"},
421   {"dw", ".dw"},
422   {"dws", ".dw %s"},
423   {"constbyte", "0x%02X"},
424   {"constword", "0x%04X"},
425   {"immedword", "#0x%04X"},
426   {"immedbyte", "#0x%02X"},
427   {"hashedstr", "#%s"},
428   {"lsbimmeds", "#<%s"},
429   {"msbimmeds", "#>%s"},
430   {"module", ".module %s"},
431   {"global", ".globl %s"},
432   {"fileprelude", ""},
433   {"functionheader",
434    "; ---------------------------------\n"
435    "; Function %s\n"
436    "; ---------------------------------"
437   },
438   {"functionlabeldef", "%s:"},
439   {"bankimmeds", "0     ; PENDING: bank support"},
440   {"los", "(%s & 0xFF)"},
441   {"his", "(%s >> 8)"},
442   {"hihis", "(%s >> 16)"},
443   {"hihihis", "(%s >> 24)"},
444   {"lod", "(%d & 0xFF)"},
445   {"hid", "(%d >> 8)"},
446   {"hihid", "(%d >> 16)"},
447   {"hihihid", "(%d >> 24)"},
448   {"lol", "(%05d$ & 0xFF)"},
449   {"hil", "(%05d$ >> 8)"},
450   {"hihil", "(%05d$ >> 16)"},
451   {"hihihil", "(%05d$ >> 24)"},
452   {"equ", "="},
453   {"org", ".org 0x%04X"},
454   {NULL, NULL}
455 };
456
457 static const ASM_MAPPING _gas_mapping[] =
458 {
459   {"labeldef", "%s::"},
460   {"slabeldef", "%s:"},
461   {"tlabeldef", "%05d$:"},
462   {"tlabel", "%05d$"},
463   {"immed", "#"},
464   {"zero", "#0x00"},
465   {"one", "#0x01"},
466   {"area", ".section %s"},
467   {"areacode", ".section %s"},
468   {"areadata", ".section %s"},
469   {"areahome", ".section %s"},
470   {"ascii", ".ascii \"%s\""},
471   {"ds", ".ds %d"},
472   {"db", ".db"},
473   {"dbs", ".db %s"},
474   {"dw", ".dw"},
475   {"dws", ".dw %s"},
476   {"constbyte", "0x%02X"},
477   {"constword", "0x%04X"},
478   {"immedword", "#0x%04X"},
479   {"immedbyte", "#0x%02X"},
480   {"hashedstr", "#%s"},
481   {"lsbimmeds", "#<%s"},
482   {"msbimmeds", "#>%s"},
483   {"module", ".file \"%s.c\""},
484   {"global", ".globl %s"},
485   {"extern", ".globl %s"},
486   {"fileprelude", ""},
487   {"functionheader",
488    "; ---------------------------------\n"
489    "; Function %s\n"
490    "; ---------------------------------"
491   },
492   {"functionlabeldef", "%s:"},
493   {"bankimmeds", "0     ; PENDING: bank support"},
494   {NULL, NULL}
495 };
496
497 static const ASM_MAPPING _a390_mapping[] =
498 {
499   {"labeldef", "%s:"},
500   {"slabeldef", "%s:"},
501   {"tlabeldef", "L%05d:"},
502   {"tlabel", "L%05d"},
503   {"immed", "#"},
504   {"zero", "#0"},
505   {"one", "#1"},
506   {"area", "; SECTION NOT SUPPORTED"},
507   {"areacode", "; SECTION NOT SUPPORTED"},
508   {"areadata", "; SECTION NOT SUPPORTED"},
509   {"areahome", "; SECTION NOT SUPPORTED"},
510   {"ascii", "db \"%s\""},
511   {"ds", "; STORAGE NOT SUPPORTED"},
512   {"db", "db"},
513   {"dbs", "db \"%s\""},
514   {"dw", "dw"},
515   {"dws", "dw %s"},
516   {"constbyte", "0%02xh"},
517   {"constword", "0%04xh"},
518   {"immedword", "#0%04Xh"},
519   {"immedbyte", "#0%02Xh"},
520   {"hashedstr", "#%s"},
521   {"lsbimmeds", "#<%s"},
522   {"msbimmeds", "#>%s"},
523   {"module", "; .file \"%s.c\""},
524   {"global", "; .globl %s"},
525   {"fileprelude", ""},
526   {"functionheader",
527    "; ---------------------------------\n"
528    "; Function %s\n"
529    "; ---------------------------------"
530   },
531   {"functionlabeldef", "%s:"},
532   {"bankimmeds", "0     ; PENDING: bank support"},
533   {"los", "(%s & 0FFh)"},
534   {"his", "((%s / 256) & 0FFh)"},
535   {"hihis", "((%s / 65536) & 0FFh)"},
536   {"hihihis", "((%s / 16777216) & 0FFh)"},
537   {"lod", "(%d & 0FFh)"},
538   {"hid", "((%d / 256) & 0FFh)"},
539   {"hihid", "((%d / 65536) & 0FFh)"},
540   {"hihihid", "((%d / 16777216) & 0FFh)"},
541   {"lol", "(L%05d & 0FFh)"},
542   {"hil", "((L%05d / 256) & 0FFh)"},
543   {"hihil", "((L%05d / 65536) & 0FFh)"},
544   {"hihihil", "((L%09d / 16777216) & 0FFh)"},
545   {"equ", " equ"},
546   {"org", ".org 0x%04X"},
547   {NULL, NULL}
548 };
549
550 static const ASM_MAPPING _xa_asm_mapping[] =
551 {
552   {"labeldef", "%s:"},
553   {"slabeldef", "%s:"},
554   {"tlabeldef", "L%05d:"},
555   {"tlabel", "L%05d"},
556   {"immed", "#"},
557   {"zero", "#0"},
558   {"one", "#1"},
559   {"area", ".area %s"},
560   {"areacode", ".area %s"},
561   {"areadata", ".area %s"},
562   {"areahome", ".area %s"},
563   {"ascii", ".db \"%s\""},
564   {"ds", ".ds %d"},
565   {"db", ".db"},
566   {"dbs", ".db \"%s\""},
567   {"dw", ".dw"},
568   {"dws", ".dw %s"},
569   {"constbyte", "0x%02x"},
570   {"constword", "0x%04x"},
571   {"immedword", "0x%04x"},
572   {"immedbyte", "0x%02x"},
573   {"hashedstr", "#%s"},
574   {"lsbimmeds", "#<%s"},
575   {"msbimmeds", "#>%s"},
576   {"module", "; .module %s"},
577   {"global", ".globl %s"},
578   {"fileprelude", ""},
579   {"functionheader",
580    "; ---------------------------------\n"
581    "; Function %s\n"
582    "; ---------------------------------"
583   },
584   {"functionlabeldef", "%s:"},
585   {"bankimmeds", "0     ; PENDING: bank support"},
586   {"los", "(%s & 0FFh)"},
587   {"his", "((%s / 256) & 0FFh)"},
588   {"hihis", "((%s / 65536) & 0FFh)"},
589   {"hihihis", "((%s / 16777216) & 0FFh)"},
590   {"lod", "(%d & 0FFh)"},
591   {"hid", "((%d / 256) & 0FFh)"},
592   {"hihid", "((%d / 65536) & 0FFh)"},
593   {"hihihid", "((%d / 16777216) & 0FFh)"},
594   {"lol", "(L%05d & 0FFh)"},
595   {"hil", "((L%05d / 256) & 0FFh)"},
596   {"hihil", "((L%05d / 65536) & 0FFh)"},
597   {"hihihil", "((L%09d / 16777216) & 0FFh)"},
598   {"equ", " equ"},
599   {NULL, NULL}
600 };
601
602 const ASM_MAPPINGS asm_asxxxx_mapping =
603 {
604   NULL,
605   _asxxxx_mapping
606 };
607
608 const ASM_MAPPINGS asm_gas_mapping =
609 {
610   NULL,
611   _gas_mapping
612 };
613
614 const ASM_MAPPINGS asm_a390_mapping =
615 {
616   NULL,
617   _a390_mapping
618 };
619
620 const ASM_MAPPINGS asm_xa_asm_mapping =
621 {
622   NULL,
623   _xa_asm_mapping
624 };