Fix asm label generation. Suppress some warning
[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 * FileBaseName(char * fileFullName)
19 {
20         char * p = fileFullName;
21
22         while (*fileFullName) {
23                 if((*fileFullName=='/')||(*fileFullName=='\\')||(*fileFullName==':')) {
24                         p = fileFullName;
25                         p++;
26                 }
27                 fileFullName++;
28         }
29         return p;
30 }
31
32 static const char *_findMapping(const char *szKey)
33 {
34     return shash_find(_h, szKey);
35 }
36
37 #if 0
38 static void _iprintf(char *pInto, const char *sz, va_list *pap)
39 {
40     char format[MAX_TOKEN_LEN];
41     char *pStart = pInto;
42     static int count;
43
44     while (*sz) {
45         if (*sz == '%') {
46             switch (*++sz) {
47                 /* See if it's a special emitter */
48             case 'r':
49                 wassert(0);
50                 break;
51             /* Name of the code segment */
52             case 'C':
53                 strcpy(pInto, CODE_NAME);
54                 pInto = pStart + strlen(pStart);
55                 sz++;
56                 break;
57             case 'F':
58                 strcpy(pInto, srcFileName);
59                 pInto = pStart + strlen(pStart);        
60                 sz++;
61                 break;
62             case 'I':
63                 sprintf(pInto, "%u", ++count);
64                 pInto = pStart + strlen(pStart);
65                 sz++;
66                 break;
67             default:
68                 {
69                     /* Scan out the arg and pass it on to sprintf */
70                     char *p = format;
71                     *p++ = '%';
72                     while (isdigit(*sz))
73                         *p++ = *sz++;
74                     *p++ = *sz++;
75                     *p = '\0';
76                     vsprintf(pInto, format, *pap);
77                     /* PENDING: Assume that the arg length was an int */
78                     (void)va_arg(*pap, int);
79                 }
80             }
81             pInto = pStart + strlen(pStart);
82         }
83         else {
84             *pInto++ = *sz++;
85         }
86     }
87     *pInto = '\0';
88 }
89
90 void tvsprintf(char *buffer, const char *sz, va_list ap)
91 {
92     char *pInto = buffer;
93     char *p;
94     char token[MAX_TOKEN_LEN];
95
96     buffer[0] = '\0';
97     
98     while (*sz) {
99         if (*sz == '!') {
100             /* Start of a token.  Search until the first
101                [non alplha, *] and call it a token. */
102             const char *t;
103             p = token;
104             sz++;
105             while (isalpha(*sz) || *sz == '*') {
106                 *p++ = *sz++;
107             }
108             *p = '\0';
109             /* Now find the token in the token list */
110             if ((t = _findMapping(token))) {
111                 printf("tvsprintf: found token \"%s\" to \"%s\"\n", token, t);
112                 _iprintf(pInto, t, &ap);
113                 pInto = buffer + strlen(buffer);
114             }
115             else {
116                 fprintf(stderr, "Cant find token \"%s\"\n", token);
117                 wassert(0);
118             }
119         }
120         else if (*sz == '%') {
121             p = token;
122             *p++ = *sz++;
123             while (!isalpha(*sz)) {
124                 *p++ = *sz++;
125             }
126             *p++ = *sz++;
127             *p = '\0';
128             vsprintf(pInto, token, ap);
129             pInto = buffer + strlen(buffer);
130             (void)va_arg(ap, int);
131         }
132         else {
133             *pInto++ = *sz++;
134         }
135     }
136     *pInto = '\0';
137 }
138 #else
139 // Append a string onto another, and update the pointer to the end of
140 // the new string.
141 static char *_appendAt(char *at, char *onto, const char *sz)
142 {
143     wassert(at && onto && sz);
144     strcpy(at, sz);
145     return at + strlen(sz);
146 }
147
148 void tvsprintf(char *buffer, const char *format, va_list ap)
149 {
150     // Under Linux PPC va_list is a structure instead of a primitive type,
151     // and doesnt like being passed around.  This version turns everything
152     // into one function.
153     
154     // Supports:
155     //  !tokens
156     //  %[CIF] - special formats with no argument (ie list isnt touched)
157     //  All of the system formats
158
159     // This is acheived by expanding the tokens and zero arg formats into
160     // one big format string, which is passed to the native printf.
161     static int count;
162     char newformat[MAX_INLINEASM];
163     char *pInto = newformat;
164     char *p;
165     char token[MAX_TOKEN_LEN];
166     const char *sz = format;
167
168     // NULL terminate it to let strlen work.
169     *pInto = '\0';
170     
171     while (*sz) {
172         if (*sz == '!') {
173             /* Start of a token.  Search until the first
174                [non alpha, *] and call it a token. */
175             const char *t;
176             p = token;
177             sz++;
178             while (isalpha(*sz) || *sz == '*') {
179                 *p++ = *sz++;
180             }
181             *p = '\0';
182             /* Now find the token in the token list */
183             if ((t = _findMapping(token))) {
184                 pInto = _appendAt(pInto, newformat, t);
185             }
186             else {
187                 fprintf(stderr, "Cant find token \"%s\"\n", token);
188                 wassert(0);
189             }
190         }
191         else if (*sz == '%') {
192             // See if its one that we handle.
193             sz++;
194             switch (*sz) {
195             case 'C':
196                 // Code segment name.
197                 pInto = _appendAt(pInto, newformat, CODE_NAME);
198                 break;
199             case 'F':
200                 // Source file name.
201                 pInto = _appendAt(pInto, newformat, srcFileName);
202                 break;
203             case 'I': {
204                 // Unique ID.
205                 char id[20];
206                 sprintf(id, "%u", ++count);
207                 pInto = _appendAt(pInto, newformat, id);
208                 break;
209             }
210             default:
211                 // Not one of ours.  Copy until the end.
212                 *pInto++ = '%';
213                 while (!isalpha(*sz)) {
214                     *pInto++ = *sz++;
215                 }
216                 *pInto++ = *sz++;
217             }
218         }
219         else {
220             *pInto++ = *sz++;
221         }
222     }
223     *pInto = '\0';
224     
225     // Now do the actual printing
226     vsprintf(buffer, newformat, ap); 
227 }
228 #endif
229
230 void tfprintf(FILE *fp, const char *szFormat, ...)
231 {
232     va_list ap;
233     char buffer[MAX_INLINEASM];
234
235     va_start(ap, szFormat);
236     tvsprintf(buffer, szFormat, ap);
237     fputs(buffer, fp);
238 }
239
240 void tsprintf(char *buffer, const char *szFormat, ...)
241 {
242     va_list ap;
243     va_start(ap, szFormat);
244     tvsprintf(buffer, szFormat, ap);
245 }
246
247 void asm_addTree(const ASM_MAPPINGS *pMappings)
248 {
249     const ASM_MAPPING *pMap;
250     /* Traverse down first */
251     if (pMappings->pParent)
252         asm_addTree(pMappings->pParent);
253     pMap = pMappings->pMappings;
254     while (pMap->szKey && pMap->szValue) {
255         shash_add(&_h, pMap->szKey, pMap->szValue);
256         pMap++;
257     }
258 }
259
260 static const ASM_MAPPING _asxxxx_mapping[] = {
261     { "labeldef", "%s::" },
262     { "slabeldef", "%s:" },
263     { "tlabeldef", "%05d$:" },
264     { "tlabel", "%05d$" },
265     { "immed", "#" },
266     { "zero", "#0x00" },
267     { "one", "#0x01" },
268     { "area", ".area %s" },
269     { "areacode", ".area %s" },
270     { "areadata", ".area %s" },
271     { "areahome", ".area %s" },
272     { "ascii", ".ascii \"%s\"" },
273     { "ds", ".ds %d" },
274     { "db", ".db" },
275     { "dbs", ".db %s" },
276     { "dw", ".dw" },
277     { "dws", ".dw %s" },
278     { "constbyte", "0x%02X" },
279     { "constword", "0x%04X" },
280     { "immedword", "#0x%04X" },
281     { "immedbyte", "#0x%02X" },
282     { "hashedstr", "#%s" },
283     { "lsbimmeds", "#<%s" },
284     { "msbimmeds", "#>%s" },
285     { "module", ".module %s" },
286     { "global", ".globl %s" },
287     { "fileprelude", "" },
288     { "functionheader", 
289       "; ---------------------------------\n"
290       "; Function %s\n"
291       "; ---------------------------------"
292     },
293     { "functionlabeldef", "%s:" },
294     { "bankimmeds", "0  ; PENDING: bank support" },
295     { NULL, NULL }
296 };
297
298 const ASM_MAPPINGS asm_asxxxx_mapping = {
299     NULL,
300     _asxxxx_mapping
301 };
302