Mercurial > projects > ldc
annotate dmd/macro.c @ 1138:4c8bb03e4fbc
Update DtoConstFP() to be correct after LLVM r67562, which changed the way the
APFloat constructor expects its i80 APInts to be formatted. (They're now
actually consistent with the x87 format)
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Tue, 24 Mar 2009 15:24:59 +0100 |
parents | b30fe7e1dbb9 |
children |
rev | line source |
---|---|
1 | 1 |
2 // Copyright (c) 1999-2006 by Digital Mars | |
3 // All Rights Reserved | |
4 // written by Walter Bright | |
5 // http://www.digitalmars.com | |
6 // License for redistribution is by either the Artistic License | |
7 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
8 // See the included readme.txt for details. | |
9 | |
10 /* Simple macro text processor. | |
11 */ | |
12 | |
13 #include <stdio.h> | |
14 #include <string.h> | |
15 #include <time.h> | |
16 #include <ctype.h> | |
17 #include <assert.h> | |
18 | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
571
diff
changeset
|
19 #include "rmem.h" |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
571
diff
changeset
|
20 #include "root.h" |
1 | 21 |
22 #include "macro.h" | |
23 | |
24 #define isidstart(c) (isalpha(c) || (c) == '_') | |
25 #define isidchar(c) (isalnum(c) || (c) == '_') | |
26 | |
27 unsigned char *memdup(unsigned char *p, size_t len) | |
28 { | |
29 return (unsigned char *)memcpy(mem.malloc(len), p, len); | |
30 } | |
31 | |
32 Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) | |
33 { | |
34 next = NULL; | |
35 | |
36 #if 1 | |
37 this->name = name; | |
38 this->namelen = namelen; | |
39 | |
40 this->text = text; | |
41 this->textlen = textlen; | |
42 #else | |
43 this->name = name; | |
44 this->namelen = namelen; | |
45 | |
46 this->text = text; | |
47 this->textlen = textlen; | |
48 #endif | |
49 inuse = 0; | |
50 } | |
51 | |
52 | |
53 Macro *Macro::search(unsigned char *name, size_t namelen) | |
54 { Macro *table; | |
55 | |
56 //printf("Macro::search(%.*s)\n", namelen, name); | |
57 for (table = this; table; table = table->next) | |
58 { | |
59 if (table->namelen == namelen && | |
60 memcmp(table->name, name, namelen) == 0) | |
61 { | |
62 //printf("\tfound %d\n", table->textlen); | |
63 break; | |
64 } | |
65 } | |
66 return table; | |
67 } | |
68 | |
69 Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) | |
70 { | |
71 //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text); | |
72 | |
73 Macro *table; | |
74 | |
75 //assert(ptable); | |
76 for (table = *ptable; table; table = table->next) | |
77 { | |
78 if (table->namelen == namelen && | |
79 memcmp(table->name, name, namelen) == 0) | |
80 { | |
81 table->text = text; | |
82 table->textlen = textlen; | |
83 return table; | |
84 } | |
85 } | |
86 table = new Macro(name, namelen, text, textlen); | |
87 table->next = *ptable; | |
88 *ptable = table; | |
89 return table; | |
90 } | |
91 | |
92 /********************************************************** | |
93 * Given buffer p[0..end], extract argument marg[0..marglen]. | |
94 * Params: | |
95 * n 0: get entire argument | |
96 * 1..9: get nth argument | |
97 * -1: get 2nd through end | |
98 */ | |
99 | |
100 unsigned extractArgN(unsigned char *p, unsigned end, unsigned char **pmarg, unsigned *pmarglen, int n) | |
101 { | |
102 /* Scan forward for matching right parenthesis. | |
103 * Nest parentheses. | |
104 * Skip over $( and $) | |
105 * Skip over "..." and '...' strings inside HTML tags. | |
106 * Skip over <!-- ... --> comments. | |
107 * Skip over previous macro insertions | |
108 * Set marglen. | |
109 */ | |
110 unsigned parens = 1; | |
111 unsigned char instring = 0; | |
112 unsigned incomment = 0; | |
113 unsigned intag = 0; | |
114 unsigned inexp = 0; | |
115 unsigned argn = 0; | |
116 | |
117 unsigned v = 0; | |
118 | |
119 Largstart: | |
120 #if 1 | |
121 // Skip first space, if any, to find the start of the macro argument | |
122 if (v < end && isspace(p[v])) | |
123 v++; | |
124 #else | |
125 // Skip past spaces to find the start of the macro argument | |
126 for (; v < end && isspace(p[v]); v++) | |
127 ; | |
128 #endif | |
129 *pmarg = p + v; | |
130 | |
131 for (; v < end; v++) | |
132 { unsigned char c = p[v]; | |
133 | |
134 switch (c) | |
135 { | |
136 case ',': | |
137 if (!inexp && !instring && !incomment && parens == 1) | |
138 { | |
139 argn++; | |
140 if (argn == 1 && n == -1) | |
141 { v++; | |
142 goto Largstart; | |
143 } | |
144 if (argn == n) | |
145 break; | |
146 if (argn + 1 == n) | |
147 { v++; | |
148 goto Largstart; | |
149 } | |
150 } | |
151 continue; | |
152 | |
153 case '(': | |
154 if (!inexp && !instring && !incomment) | |
155 parens++; | |
156 continue; | |
157 | |
158 case ')': | |
159 if (!inexp && !instring && !incomment && --parens == 0) | |
160 { | |
161 break; | |
162 } | |
163 continue; | |
164 | |
165 case '"': | |
166 case '\'': | |
167 if (!inexp && !incomment && intag) | |
168 { | |
169 if (c == instring) | |
170 instring = 0; | |
171 else if (!instring) | |
172 instring = c; | |
173 } | |
174 continue; | |
175 | |
176 case '<': | |
177 if (!inexp && !instring && !incomment) | |
178 { | |
179 if (v + 6 < end && | |
180 p[v + 1] == '!' && | |
181 p[v + 2] == '-' && | |
182 p[v + 3] == '-') | |
183 { | |
184 incomment = 1; | |
185 v += 3; | |
186 } | |
187 else if (v + 2 < end && | |
188 isalpha(p[v + 1])) | |
189 intag = 1; | |
190 } | |
191 continue; | |
192 | |
193 case '>': | |
194 if (!inexp) | |
195 intag = 0; | |
196 continue; | |
197 | |
198 case '-': | |
199 if (!inexp && | |
200 !instring && | |
201 incomment && | |
202 v + 2 < end && | |
203 p[v + 1] == '-' && | |
204 p[v + 2] == '>') | |
205 { | |
206 incomment = 0; | |
207 v += 2; | |
208 } | |
209 continue; | |
210 | |
211 case 0xFF: | |
212 if (v + 1 < end) | |
213 { | |
214 if (p[v + 1] == '{') | |
215 inexp++; | |
216 else if (p[v + 1] == '}') | |
217 inexp--; | |
218 } | |
219 continue; | |
220 | |
221 default: | |
222 continue; | |
223 } | |
224 break; | |
225 } | |
226 if (argn == 0 && n == -1) | |
227 *pmarg = p + v; | |
228 *pmarglen = p + v - *pmarg; | |
229 //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg); | |
230 return v; | |
231 } | |
232 | |
233 | |
234 /***************************************************** | |
235 * Expand macro in place in buf. | |
236 * Only look at the text in buf from start to end. | |
237 */ | |
238 | |
239 void Macro::expand(OutBuffer *buf, unsigned start, unsigned *pend, | |
240 unsigned char *arg, unsigned arglen) | |
241 { | |
242 #if 0 | |
243 printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg); | |
244 printf("Buf is: '%.*s'\n", *pend - start, buf->data + start); | |
245 #endif | |
246 | |
247 static int nest; | |
248 if (nest > 100) // limit recursive expansion | |
249 return; | |
250 nest++; | |
251 | |
252 unsigned end = *pend; | |
253 assert(start <= end); | |
254 assert(end <= buf->offset); | |
255 | |
256 /* First pass - replace $0 | |
257 */ | |
258 arg = memdup(arg, arglen); | |
259 for (unsigned u = start; u + 1 < end; ) | |
260 { | |
261 unsigned char *p = buf->data; // buf->data is not loop invariant | |
262 | |
263 /* Look for $0, but not $$0, and replace it with arg. | |
264 */ | |
265 if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+')) | |
266 { | |
267 if (u > start && p[u - 1] == '$') | |
268 { // Don't expand $$0, but replace it with $0 | |
269 buf->remove(u - 1, 1); | |
270 end--; | |
271 u += 1; // now u is one past the closing '1' | |
272 continue; | |
273 } | |
274 | |
275 unsigned char c = p[u + 1]; | |
276 int n = (c == '+') ? -1 : c - '0'; | |
277 | |
278 unsigned char *marg; | |
279 unsigned marglen; | |
280 extractArgN(arg, arglen, &marg, &marglen, n); | |
281 if (marglen == 0) | |
282 { // Just remove macro invocation | |
283 //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); | |
284 buf->remove(u, 2); | |
285 end -= 2; | |
286 } | |
287 else if (c == '+') | |
288 { | |
289 // Replace '$+' with 'arg' | |
290 //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); | |
291 buf->remove(u, 2); | |
292 buf->insert(u, marg, marglen); | |
293 end += marglen - 2; | |
294 | |
295 // Scan replaced text for further expansion | |
296 unsigned mend = u + marglen; | |
297 expand(buf, u, &mend, NULL, 0); | |
298 end += mend - (u + marglen); | |
299 u = mend; | |
300 } | |
301 else | |
302 { | |
303 // Replace '$1' with '\xFF{arg\xFF}' | |
304 //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg); | |
305 buf->data[u] = 0xFF; | |
306 buf->data[u + 1] = '{'; | |
307 buf->insert(u + 2, marg, marglen); | |
308 buf->insert(u + 2 + marglen, "\xFF}", 2); | |
309 end += -2 + 2 + marglen + 2; | |
310 | |
311 // Scan replaced text for further expansion | |
312 unsigned mend = u + 2 + marglen; | |
313 expand(buf, u + 2, &mend, NULL, 0); | |
314 end += mend - (u + 2 + marglen); | |
315 u = mend; | |
316 } | |
317 //printf("u = %d, end = %d\n", u, end); | |
318 //printf("#%.*s#\n", end, &buf->data[0]); | |
319 continue; | |
320 } | |
321 | |
322 u++; | |
323 } | |
324 | |
325 /* Second pass - replace other macros | |
326 */ | |
327 for (unsigned u = start; u + 4 < end; ) | |
328 { | |
329 unsigned char *p = buf->data; // buf->data is not loop invariant | |
330 | |
331 /* A valid start of macro expansion is $(c, where c is | |
332 * an id start character, and not $$(c. | |
333 */ | |
334 if (p[u] == '$' && p[u + 1] == '(' && isidstart(p[u + 2])) | |
335 { | |
336 //printf("\tfound macro start '%c'\n", p[u + 2]); | |
337 unsigned char *name = p + u + 2; | |
338 unsigned namelen = 0; | |
339 | |
340 unsigned char *marg; | |
341 unsigned marglen; | |
342 | |
343 unsigned v; | |
344 /* Scan forward to find end of macro name and | |
345 * beginning of macro argument (marg). | |
346 */ | |
347 for (v = u + 2; v < end; v++) | |
348 { unsigned char c = p[v]; | |
349 | |
350 if (!isidchar(c)) | |
351 { // We've gone past the end of the macro name. | |
352 namelen = v - (u + 2); | |
353 break; | |
354 } | |
355 } | |
356 | |
357 v += extractArgN(p + v, end - v, &marg, &marglen, 0); | |
358 assert(v <= end); | |
359 | |
360 if (v < end) | |
361 { // v is on the closing ')' | |
362 if (u > start && p[u - 1] == '$') | |
363 { // Don't expand $$(NAME), but replace it with $(NAME) | |
364 buf->remove(u - 1, 1); | |
365 end--; | |
366 u = v; // now u is one past the closing ')' | |
367 continue; | |
368 } | |
369 | |
370 Macro *m = search(name, namelen); | |
371 if (m) | |
372 { | |
373 #if 0 | |
374 if (m->textlen && m->text[0] == ' ') | |
375 { m->text++; | |
376 m->textlen--; | |
377 } | |
378 #endif | |
379 if (m->inuse && marglen == 0) | |
380 { // Remove macro invocation | |
381 buf->remove(u, v + 1 - u); | |
382 end -= v + 1 - u; | |
383 } | |
384 else if (m->inuse && arglen == marglen && memcmp(arg, marg, arglen) == 0) | |
385 { // Recursive expansion; just leave in place | |
386 | |
387 } | |
388 else | |
389 { | |
390 //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text); | |
391 #if 1 | |
392 marg = memdup(marg, marglen); | |
393 // Insert replacement text | |
394 buf->spread(v + 1, 2 + m->textlen + 2); | |
395 buf->data[v + 1] = 0xFF; | |
396 buf->data[v + 2] = '{'; | |
397 memcpy(buf->data + v + 3, m->text, m->textlen); | |
398 buf->data[v + 3 + m->textlen] = 0xFF; | |
399 buf->data[v + 3 + m->textlen + 1] = '}'; | |
400 | |
401 end += 2 + m->textlen + 2; | |
402 | |
403 // Scan replaced text for further expansion | |
404 m->inuse++; | |
405 unsigned mend = v + 1 + 2+m->textlen+2; | |
406 expand(buf, v + 1, &mend, marg, marglen); | |
407 end += mend - (v + 1 + 2+m->textlen+2); | |
408 m->inuse--; | |
409 | |
410 buf->remove(u, v + 1 - u); | |
411 end -= v + 1 - u; | |
412 u += mend - (v + 1); | |
413 #else | |
414 // Insert replacement text | |
415 buf->insert(v + 1, m->text, m->textlen); | |
416 end += m->textlen; | |
417 | |
418 // Scan replaced text for further expansion | |
419 m->inuse++; | |
420 unsigned mend = v + 1 + m->textlen; | |
421 expand(buf, v + 1, &mend, marg, marglen); | |
422 end += mend - (v + 1 + m->textlen); | |
423 m->inuse--; | |
424 | |
425 buf->remove(u, v + 1 - u); | |
426 end -= v + 1 - u; | |
427 u += mend - (v + 1); | |
428 #endif | |
429 mem.free(marg); | |
430 //printf("u = %d, end = %d\n", u, end); | |
431 //printf("#%.*s#\n", end - u, &buf->data[u]); | |
432 continue; | |
433 } | |
434 } | |
435 else | |
436 { | |
437 // Replace $(NAME) with nothing | |
438 buf->remove(u, v + 1 - u); | |
439 end -= (v + 1 - u); | |
440 continue; | |
441 } | |
442 } | |
443 } | |
444 u++; | |
445 } | |
446 mem.free(arg); | |
447 *pend = end; | |
448 nest--; | |
449 } |