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