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