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