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