9269fc7ef6a606c900212b3747bf371fc2ffa3a6
[fw/sdcc] / src / asm.c
1 /** @file asm.c
2     Provides output functions that modify the output string
3     based on the input tokens and the assembler token mapping
4     specification loaded.
5
6     Note that the functions below only handle digit format modifiers.
7     eg %02X is ok, but %lu and %.4u will fail.
8 */
9 #include "common.h"
10 #include "asm.h"
11
12 /* A 'token' is like !blah or %24f and is under the programmers
13    control. */
14 #define MAX_TOKEN_LEN           64
15
16 static hTab *_h;
17
18 char *
19 FileBaseName (char *fileFullName)
20 {
21   char *p = fileFullName;
22
23   if (!fileFullName) {
24     return "unknown";
25   }
26
27   while (*fileFullName)
28     {
29       if ((*fileFullName == '/') || (*fileFullName == '\\') || (*fileFullName == ':'))
30         {
31           p = fileFullName;
32           p++;
33         }
34       fileFullName++;
35     }
36   return p;
37 }
38
39 static const char *
40 _findMapping (const char *szKey)
41 {
42   return shash_find (_h, szKey);
43 }
44
45 // Append a string onto another, and update the pointer to the end of
46 // the new string.
47 static char *
48 _appendAt (char *at, char *onto, const char *sz, size_t *max)
49 {
50   wassert (at && onto && sz);
51   strncpyz (at, sz, *max);
52   *max -= strlen (at);
53   return at + strlen (at);
54 }
55
56 void 
57 tvsprintf (char *buffer, size_t len, const char *format, va_list ap)
58 {
59   // Under Linux PPC va_list is a structure instead of a primitive type,
60   // and doesnt like being passed around.  This version turns everything
61   // into one function.
62
63   // Supports:
64   //  !tokens
65   //  %[CIFN] - special formats with no argument (ie list isnt touched)
66   //  All of the system formats
67
68   // This is acheived by expanding the tokens and zero arg formats into
69   // one big format string, which is passed to the native printf.
70   static int    count;
71   char          noTokens[INITIAL_INLINEASM];
72   char          newFormat[INITIAL_INLINEASM];
73   char          *pInto = noTokens;
74   size_t        pIntoLen = sizeof(noTokens);
75   char          *p;
76   char          token[MAX_TOKEN_LEN];
77   const char    *sz = format;
78
79   // NULL terminate it to let strlen work.
80   *pInto = '\0';
81
82   /* First pass: expand all of the macros */
83   while (pIntoLen && *sz)
84     {
85       if (*sz == '!')
86         {
87           /* Start of a token.  Search until the first
88              [non alpha, *] and call it a token. */
89           const char *t;
90           p = token;
91           sz++;
92           while (isalpha (*sz) || *sz == '*')
93             {
94               *p++ = *sz++;
95             }
96           *p = '\0';
97           /* Now find the token in the token list */
98           if ((t = _findMapping (token)))
99             {
100               pInto = _appendAt (pInto, noTokens, t, &pIntoLen);
101             }
102           else
103             {
104               fprintf (stderr, "Cant find token \"%s\"\n", token);
105               wassert (0);
106             }
107         }
108       else
109         {
110           *pInto++ = *sz++;
111           pIntoLen--;
112         }
113     }
114
115   if (!pIntoLen)
116   {
117       fprintf(stderr,
118                 "Internal error: tvsprintf overflowed on pass one.\n");
119       // Might as well go on...
120   }
121     
122   *pInto = '\0';
123
124   /* Second pass: Expand any macros that we own */
125   sz = noTokens;
126   pInto = newFormat;
127   pIntoLen = sizeof(newFormat);
128
129   while (pIntoLen && *sz)
130     {
131       if (*sz == '%')
132         {
133           // See if its one that we handle.
134           sz++;
135           switch (*sz)
136             {
137             case 'C':
138               // Code segment name.
139               pInto = _appendAt (pInto, newFormat, CODE_NAME, &pIntoLen);
140               sz++;
141               break;
142             case 'F':
143               // Source file name.
144               pInto = _appendAt (pInto, newFormat, fullSrcFileName, &pIntoLen);
145               sz++;
146               break;
147             case 'N':
148               // Current function name.
149               pInto = _appendAt (pInto, newFormat, currFunc->rname, &pIntoLen);
150               sz++;
151               break;
152             case 'I':
153               {
154                 // Unique ID.
155                 char id[20];
156                 SNPRINTF (id, sizeof(id), "%u", ++count);
157                 pInto = _appendAt (pInto, newFormat, id, &pIntoLen);
158                 sz++;
159                 break;
160               }
161             default:
162               // Not one of ours.  Copy until the end.
163               *pInto++ = '%';
164               pIntoLen--;
165               while (pIntoLen && !isalpha (*sz))
166                 {
167                   *pInto++ = *sz++;
168                   pIntoLen--;
169                 }
170                 if (pIntoLen)
171                 {
172                     *pInto++ = *sz++;
173                     pIntoLen--;
174                 }
175             }
176         }
177       else
178         {
179           *pInto++ = *sz++;
180           pIntoLen--;
181         }
182     }
183
184   if (!pIntoLen)
185   {
186       fprintf(stderr,
187                 "Internal error: tvsprintf overflowed on pass two.\n");
188       // Might as well go on...
189   }    
190     
191   *pInto = '\0';
192
193   // Now do the actual printing
194 #if defined(HAVE_VSNPRINTF)
195     {
196         int wrlen;
197         wrlen = vsnprintf (buffer, len, newFormat, ap);
198         
199         if (wrlen < 0 || (size_t)wrlen >= len)
200         {
201             fprintf(stderr, "Internal error: tvsprintf truncated.\n");
202         }
203     }
204     
205 #else    
206     vsprintf (buffer, newFormat, ap);
207     if (strlen(buffer) >= len)
208     {
209         fprintf(stderr, "Internal error: tvsprintf overflowed.\n");
210     }
211 #endif    
212 }
213
214 void 
215 tfprintf (FILE * fp, const char *szFormat,...)
216 {
217   va_list ap;
218   char buffer[INITIAL_INLINEASM];
219
220   va_start (ap, szFormat);
221   tvsprintf (buffer, INITIAL_INLINEASM, szFormat, ap);
222   va_end(ap);
223   fputs (buffer, fp);
224 }
225
226 void 
227 tsprintf (char *buffer, size_t len, const char *szFormat,...)
228 {
229   va_list ap;
230   va_start (ap, szFormat);
231   tvsprintf (buffer, len, szFormat, ap);
232   va_end(ap);
233 }
234
235 void 
236 asm_addTree (const ASM_MAPPINGS * pMappings)
237 {
238   const ASM_MAPPING *pMap;
239
240   /* Traverse down first */
241   if (pMappings->pParent)
242     asm_addTree (pMappings->pParent);
243   pMap = pMappings->pMappings;
244   while (pMap->szKey && pMap->szValue) {
245       shash_add (&_h, pMap->szKey, pMap->szValue);
246       pMap++;
247   }
248 }
249
250 /*-----------------------------------------------------------------*/
251 /* printILine - return the readable i-code for this ic             */
252 /*                                                                 */
253 /* iCodePrint wants a file stream so we need a temporary file to   */
254 /* fool it                                                         */
255 /*-----------------------------------------------------------------*/
256 char *
257 printILine (iCode *ic)
258 {
259   static char verbalICode[1024];
260   FILE *tmpFile;
261   iCodeTable *icTab=getTableEntry(ic->op);
262
263   if (INLINEASM == ic->op)
264     return "inline";
265
266   tmpFile = tempfile();
267   assert(NULL != tmpFile);
268   if (NULL == tmpFile)
269     return "";  /* return empty line if temporary file creation failed */
270
271   addSetHead(&tmpfileSet, tmpFile);
272
273   /* stuff the temporary file with the readable icode */
274   icTab->iCodePrint(tmpFile, ic, icTab->printName);
275
276   /* now swallow it */
277   rewind(tmpFile);
278   fgets(verbalICode, sizeof(verbalICode), tmpFile);
279
280   /* clean up the mess, we'll return here for all icodes!!
281    * Actually the temporary file is only closed. It will be
282    * removed by rm_tmpfiles().
283    */
284   assert(!fclose(tmpFile));
285   deleteSetItem(&tmpfileSet, tmpFile);
286
287   /* kill the trailing NL */
288   if ('\n' == verbalICode[strlen(verbalICode) - 1])
289     verbalICode[strlen(verbalICode) - 1] = '\0';
290
291   /* and throw it up */
292   return verbalICode;
293 }
294
295 /*-----------------------------------------------------------------*/
296 /* printCLine - return the c-code for this lineno                  */
297 /*-----------------------------------------------------------------*/
298 /* int rewinds=0; */
299 char *
300 printCLine (char *srcFile, int lineno)
301 {
302   static FILE *inFile=NULL;
303   static char inLineString[1024];
304   static int inLineNo=0;
305   static char lastSrcFile[PATH_MAX];
306   char *ilsP=inLineString;
307
308   if (inFile) {
309     if (strcmp (lastSrcFile, srcFile) != 0) {
310       fclose (inFile);
311       inFile = NULL;
312       inLineNo = 0;
313     }
314   }
315   if (!inFile) {
316     inFile=fopen(srcFile, "r");
317     if (!inFile) {
318       perror ("printCLine");
319       exit (1);
320     }
321     strncpyz (lastSrcFile, srcFile, PATH_MAX);
322   }
323   if (lineno<inLineNo) {
324     fseek (inFile, 0, SEEK_SET);
325     inLineNo=0;
326     /* rewinds++; */
327   }
328   while (fgets (inLineString, 1024, inFile)) {
329     inLineNo++;
330     if (inLineNo==lineno) {
331       // remove the trailing NL
332       inLineString[strlen(inLineString)-1]='\0';
333       break;
334     }
335   }
336   while (isspace ((int)*ilsP))
337     ilsP++;
338
339   return ilsP;
340 }
341
342 static const ASM_MAPPING _asxxxx_mapping[] =
343 {
344   {"labeldef", "%s::"},
345   {"slabeldef", "%s:"},
346   {"tlabeldef", "%05d$:"},
347   {"tlabel", "%05d$"},
348   {"immed", "#"},
349   {"zero", "#0x00"},
350   {"one", "#0x01"},
351   {"area", ".area %s"},
352   {"areacode", ".area %s"},
353   {"areadata", ".area %s"},
354   {"areahome", ".area %s"},
355   {"ascii", ".ascii \"%s\""},
356   {"ds", ".ds %d"},
357   {"db", ".db"},
358   {"dbs", ".db %s"},
359   {"dw", ".dw"},
360   {"dws", ".dw %s"},
361   {"constbyte", "0x%02X"},
362   {"constword", "0x%04X"},
363   {"immedword", "#0x%04X"},
364   {"immedbyte", "#0x%02X"},
365   {"hashedstr", "#%s"},
366   {"lsbimmeds", "#<%s"},
367   {"msbimmeds", "#>%s"},
368   {"module", ".module %s"},
369   {"global", ".globl %s"},
370   {"fileprelude", ""},
371   {"functionheader",
372    "; ---------------------------------\n"
373    "; Function %s\n"
374    "; ---------------------------------"
375   },
376   {"functionlabeldef", "%s:"},
377   {"bankimmeds", "0     ; PENDING: bank support"},
378   {"los","(%s & 0xFF)"},
379   {"his","(%s >> 8)"},
380   {"hihis","(%s >> 16)"},
381   {"hihihis","(%s >> 24)"},
382   {"lod","(%d & 0xFF)"},
383   {"hid","(%d >> 8)"},
384   {"hihid","(%d >> 16)"},
385   {"hihihid","(%d >> 24)"},
386   {"lol","(%05d$ & 0xFF)"},
387   {"hil","(%05d$ >> 8)"},
388   {"hihil","(%05d$ >> 16)"},
389   {"hihihil","(%05d$ >> 24)"},
390   {"equ","="},
391   {NULL, NULL}
392 };
393
394 static const ASM_MAPPING _gas_mapping[] =
395 {
396   {"labeldef", "%s::"},
397   {"slabeldef", "%s:"},
398   {"tlabeldef", "%05d$:"},
399   {"tlabel", "%05d$"},
400   {"immed", "#"},
401   {"zero", "#0x00"},
402   {"one", "#0x01"},
403   {"area", ".section %s"},
404   {"areacode", ".section %s"},
405   {"areadata", ".section %s"},
406   {"areahome", ".section %s"},
407   {"ascii", ".ascii \"%s\""},
408   {"ds", ".ds %d"},
409   {"db", ".db"},
410   {"dbs", ".db %s"},
411   {"dw", ".dw"},
412   {"dws", ".dw %s"},
413   {"constbyte", "0x%02X"},
414   {"constword", "0x%04X"},
415   {"immedword", "#0x%04X"},
416   {"immedbyte", "#0x%02X"},
417   {"hashedstr", "#%s"},
418   {"lsbimmeds", "#<%s"},
419   {"msbimmeds", "#>%s"},
420   {"module", ".file \"%s.c\""},
421   {"global", ".globl %s"},
422   {"extern", ".globl %s"},
423   {"fileprelude", ""},
424   {"functionheader",
425    "; ---------------------------------\n"
426    "; Function %s\n"
427    "; ---------------------------------"
428   },
429   {"functionlabeldef", "%s:"},
430   {"bankimmeds", "0     ; PENDING: bank support"},  
431   {NULL, NULL}
432 };
433
434 static const ASM_MAPPING _a390_mapping[] =
435 {
436   {"labeldef", "%s:"},
437   {"slabeldef", "%s:"},
438   {"tlabeldef", "L%05d:"},
439   {"tlabel", "L%05d"},
440   {"immed", "#"},
441   {"zero", "#0"},
442   {"one", "#1"},
443   {"area", "; SECTION NOT SUPPORTED"},
444   {"areacode", "; SECTION NOT SUPPORTED"},
445   {"areadata", "; SECTION NOT SUPPORTED"},
446   {"areahome", "; SECTION NOT SUPPORTED"},
447   {"ascii", "db \"%s\""},
448   {"ds", "; STORAGE NOT SUPPORTED"},
449   {"db", "db"},
450   {"dbs", "db \"%s\""},
451   {"dw", "dw"},
452   {"dws", "dw %s"},
453   {"constbyte", "0%02xh"},
454   {"constword", "0%04xh"},
455   {"immedword", "#0%04Xh"},
456   {"immedbyte", "#0%02Xh"},
457   {"hashedstr", "#%s"},
458   {"lsbimmeds", "#<%s"},
459   {"msbimmeds", "#>%s"},
460   {"module", "; .file \"%s.c\""},
461   {"global", "; .globl %s"},
462   {"fileprelude", ""},
463   {"functionheader",
464    "; ---------------------------------\n"
465    "; Function %s\n"
466    "; ---------------------------------"
467   },
468   {"functionlabeldef", "%s:"},
469   {"bankimmeds", "0     ; PENDING: bank support"},  
470   {"los","(%s & 0FFh)"},
471   {"his","((%s / 256) & 0FFh)"},
472   {"hihis","((%s / 65536) & 0FFh)"},
473   {"hihihis","((%s / 16777216) & 0FFh)"},
474   {"lod","(%d & 0FFh)"},
475   {"hid","((%d / 256) & 0FFh)"},
476   {"hihid","((%d / 65536) & 0FFh)"},
477   {"hihihid","((%d / 16777216) & 0FFh)"},
478   {"lol","(L%05d & 0FFh)"},
479   {"hil","((L%05d / 256) & 0FFh)"},
480   {"hihil","((L%05d / 65536) & 0FFh)"},
481   {"hihihil","((L%09d / 16777216) & 0FFh)"},
482   {"equ"," equ"},
483   {NULL, NULL}
484 };
485
486 static const ASM_MAPPING _xa_asm_mapping[] =
487 {
488   {"labeldef", "%s:"},
489   {"slabeldef", "%s:"},
490   {"tlabeldef", "L%05d:"},
491   {"tlabel", "L%05d"},
492   {"immed", "#"},
493   {"zero", "#0"},
494   {"one", "#1"},
495   {"area", ".area %s"},
496   {"areacode", ".area %s"},
497   {"areadata", ".area %s"},
498   {"areahome", ".area %s"},
499   {"ascii", ".db \"%s\""},
500   {"ds", ".ds %d"},
501   {"db", ".db"},
502   {"dbs", ".db \"%s\""},
503   {"dw", ".dw"},
504   {"dws", ".dw %s"},
505   {"constbyte", "0x%02x"},
506   {"constword", "0x%04x"},
507   {"immedword", "0x%04x"},
508   {"immedbyte", "0x%02x"},
509   {"hashedstr", "#%s"},
510   {"lsbimmeds", "#<%s"},
511   {"msbimmeds", "#>%s"},
512   {"module", "; .module %s"},
513   {"global", ".globl %s"},
514   {"fileprelude", ""},
515   {"functionheader",
516    "; ---------------------------------\n"
517    "; Function %s\n"
518    "; ---------------------------------"
519   },
520   {"functionlabeldef", "%s:"},
521   {"bankimmeds", "0     ; PENDING: bank support"},  
522   {"los","(%s & 0FFh)"},
523   {"his","((%s / 256) & 0FFh)"},
524   {"hihis","((%s / 65536) & 0FFh)"},
525   {"hihihis","((%s / 16777216) & 0FFh)"},
526   {"lod","(%d & 0FFh)"},
527   {"hid","((%d / 256) & 0FFh)"},
528   {"hihid","((%d / 65536) & 0FFh)"},
529   {"hihihid","((%d / 16777216) & 0FFh)"},
530   {"lol","(L%05d & 0FFh)"},
531   {"hil","((L%05d / 256) & 0FFh)"},
532   {"hihil","((L%05d / 65536) & 0FFh)"},
533   {"hihihil","((L%09d / 16777216) & 0FFh)"},
534   {"equ"," equ"},
535   {NULL, NULL}
536 };
537
538 const ASM_MAPPINGS asm_asxxxx_mapping =
539 {
540   NULL,
541   _asxxxx_mapping
542 };
543
544 const ASM_MAPPINGS asm_gas_mapping =
545 {
546   NULL,
547   _gas_mapping
548 };
549
550 const ASM_MAPPINGS asm_a390_mapping =
551 {
552   NULL,
553   _a390_mapping
554 };
555
556 const ASM_MAPPINGS asm_xa_asm_mapping =
557 {
558   NULL,
559   _xa_asm_mapping
560 };