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