17
|
1 #include <stdlib.h>
|
|
2 #include <string.h>
|
|
3
|
|
4 #include "array.h"
|
|
5 #include "mode.h"
|
|
6 #include "place.h"
|
|
7 #include "macro.h"
|
|
8
|
|
9 struct macro {
|
|
10 struct place defplace;
|
|
11 struct place expansionplace;
|
|
12 unsigned hash;
|
|
13 char *name;
|
|
14 char *expansion;
|
|
15 };
|
|
16 DECLARRAY(macro);
|
|
17 DEFARRAY(macro, );
|
|
18 DECLARRAY(macroarray);
|
|
19 DEFARRAY(macroarray, );
|
|
20
|
|
21 static struct macroarrayarray macros;
|
|
22 static unsigned total_macros;
|
|
23 static unsigned hashmask;
|
|
24
|
|
25 ////////////////////////////////////////////////////////////
|
|
26 // macro structure ops
|
|
27
|
|
28 static
|
|
29 struct macro *
|
|
30 macro_create(struct place *p1, struct place *p2, unsigned hash,
|
|
31 const char *name, const char *expansion)
|
|
32 {
|
|
33 struct macro *m;
|
|
34
|
|
35 m = domalloc(sizeof(*m));
|
|
36 m->defplace = *p1;
|
|
37 m->expansionplace = *p2;
|
|
38 m->hash = hash;
|
|
39 m->name = dostrdup(name);
|
|
40 m->expansion = dostrdup(expansion);
|
|
41 return m;
|
|
42 }
|
|
43
|
|
44 static
|
|
45 void
|
|
46 macro_destroy(struct macro *m)
|
|
47 {
|
|
48 free(m->name);
|
|
49 free(m->expansion);
|
|
50 free(m);
|
|
51 }
|
|
52
|
|
53 ////////////////////////////////////////////////////////////
|
|
54 // macro table
|
|
55
|
|
56 /*
|
|
57 * Unless I've screwed up, this is something called Fletcher's Checksum
|
|
58 * that showed up in Dr. Dobbs in, according to my notes, May 1992. The
|
|
59 * implementation is new.
|
|
60 */
|
|
61 static
|
|
62 unsigned
|
|
63 hashfunc(const char *s)
|
|
64 {
|
|
65 uint16_t x1, x2, a;
|
|
66 size_t i, len;
|
|
67
|
|
68 len = strlen(s);
|
|
69
|
|
70 x1 = (uint16_t) (len >> 16);
|
|
71 x2 = (uint16_t) (len);
|
|
72 if (x1==0) {
|
|
73 x1++;
|
|
74 }
|
|
75 if (x2==0) {
|
|
76 x2++;
|
|
77 }
|
|
78
|
|
79 for (i=0; i<len; i+=2) {
|
|
80 if (i==len-1) {
|
|
81 a = (unsigned char)s[i];
|
|
82 /* don't run off the end of the array */
|
|
83 }
|
|
84 else {
|
|
85 a = (unsigned char)s[i] +
|
|
86 ((uint16_t)(unsigned char)s[i+1] << 8);
|
|
87 }
|
|
88 x1 += a;
|
|
89 if (x1 < a) {
|
|
90 x1++;
|
|
91 }
|
|
92 x2 += x1;
|
|
93 if (x2 < x1) {
|
|
94 x2++;
|
|
95 }
|
|
96 }
|
|
97
|
|
98 x1 ^= 0xffff;
|
|
99 x2 ^= 0xffff;
|
|
100 return ((uint32_t)x2)*65535U + x1;
|
|
101 }
|
|
102
|
|
103 static
|
|
104 void
|
|
105 macrotable_init(void)
|
|
106 {
|
|
107 unsigned i;
|
|
108
|
|
109 macroarrayarray_init(¯os);
|
|
110 macroarrayarray_setsize(¯os, 4);
|
|
111 for (i=0; i<4; i++) {
|
|
112 macroarrayarray_set(¯os, i, NULL);
|
|
113 }
|
|
114 total_macros = 0;
|
|
115 hashmask = 0x3;
|
|
116 }
|
|
117
|
|
118 DESTROYALL_ARRAY(macro, );
|
|
119
|
|
120 static
|
|
121 void
|
|
122 macrotable_cleanup(void)
|
|
123 {
|
|
124 struct macroarray *bucket;
|
|
125 unsigned numbuckets, i;
|
|
126
|
|
127 numbuckets = macroarrayarray_num(¯os);
|
|
128 for (i=0; i<numbuckets; i++) {
|
|
129 bucket = macroarrayarray_get(¯os, i);
|
|
130 macroarray_destroyall(bucket);
|
|
131 macroarray_destroy(bucket);
|
|
132 }
|
|
133 macroarrayarray_setsize(¯os, 0);
|
|
134 macroarrayarray_cleanup(¯os);
|
|
135 }
|
|
136
|
|
137 static
|
|
138 struct macro *
|
|
139 macrotable_find(const char *name, bool remove)
|
|
140 {
|
|
141 unsigned hash;
|
|
142 struct macroarray *bucket;
|
|
143 struct macro *m, *m2;
|
|
144 unsigned i, num;
|
|
145
|
|
146 hash = hashfunc(name);
|
|
147 bucket = macroarrayarray_get(¯os, hash & hashmask);
|
|
148 if (bucket == NULL) {
|
|
149 return NULL;
|
|
150 }
|
|
151 num = macroarray_num(bucket);
|
|
152 for (i=0; i<num; i++) {
|
|
153 m = macroarray_get(bucket, i);
|
|
154 if (hash != m->hash) {
|
|
155 continue;
|
|
156 }
|
|
157 if (!strcmp(name, m->name)) {
|
|
158 if (remove) {
|
|
159 if (i < num-1) {
|
|
160 m2 = macroarray_get(bucket, num-1);
|
|
161 macroarray_set(bucket, i, m2);
|
|
162 }
|
|
163 macroarray_setsize(bucket, num-1);
|
|
164 total_macros--;
|
|
165 }
|
|
166 return m;
|
|
167 }
|
|
168 }
|
|
169 return NULL;
|
|
170 }
|
|
171
|
|
172 static
|
|
173 void
|
|
174 macrotable_rehash(void)
|
|
175 {
|
|
176 struct macroarray *newbucket, *oldbucket;
|
|
177 struct macro *m;
|
|
178 unsigned newmask, tossbit;
|
|
179 unsigned numbuckets, i;
|
|
180 unsigned oldnum, j, k;
|
|
181
|
|
182 numbuckets = macroarrayarray_num(¯os);
|
|
183 macroarrayarray_setsize(¯os, numbuckets*2);
|
|
184
|
|
185 assert(hashmask == numbuckets - 1);
|
|
186 newmask = (hashmask << 1) | 1U;
|
|
187 tossbit = newmask && ~hashmask;
|
|
188 hashmask = newmask;
|
|
189
|
|
190 for (i=0; i<numbuckets; i++) {
|
|
191 newbucket = NULL;
|
|
192 oldbucket = macroarrayarray_get(¯os, i);
|
|
193 oldnum = macroarray_num(oldbucket);
|
|
194 for (j=0; j<oldnum; j++) {
|
|
195 m = macroarray_get(oldbucket, j);
|
|
196 if (m->hash & tossbit) {
|
|
197 if (newbucket == NULL) {
|
|
198 newbucket = macroarray_create();
|
|
199 }
|
|
200 macroarray_set(oldbucket, j, NULL);
|
|
201 macroarray_add(newbucket, m, NULL);
|
|
202 }
|
|
203 }
|
|
204 for (j=k=0; j<oldnum; j++) {
|
|
205 m = macroarray_get(oldbucket, j);
|
|
206 if (m != NULL && k < j) {
|
|
207 macroarray_set(oldbucket, k++, m);
|
|
208 }
|
|
209 }
|
|
210 macroarray_setsize(oldbucket, k);
|
|
211 macroarrayarray_set(¯os, numbuckets + i, newbucket);
|
|
212 }
|
|
213 }
|
|
214
|
|
215 static
|
|
216 void
|
|
217 macrotable_add(struct macro *m)
|
|
218 {
|
|
219 unsigned hash;
|
|
220 struct macroarray *bucket;
|
|
221 unsigned numbuckets;
|
|
222
|
|
223 numbuckets = macroarrayarray_num(¯os);
|
|
224 if (total_macros > 0 && total_macros / numbuckets > 9) {
|
|
225 macrotable_rehash();
|
|
226 }
|
|
227
|
|
228 hash = hashfunc(m->name);
|
|
229 bucket = macroarrayarray_get(¯os, hash & hashmask);
|
|
230 if (bucket == NULL) {
|
|
231 bucket = macroarray_create();
|
|
232 macroarrayarray_set(¯os, hash & hashmask, bucket);
|
|
233 }
|
|
234 macroarray_add(bucket, m, NULL);
|
|
235 total_macros++;
|
|
236 }
|
|
237
|
|
238 ////////////////////////////////////////////////////////////
|
|
239 // external macro definition interface
|
|
240
|
|
241 void
|
|
242 macro_define(struct place *p1, const char *macro,
|
|
243 struct place *p2, const char *expansion)
|
|
244 {
|
|
245 struct macro *m;
|
|
246
|
|
247 m = macrotable_find(macro, false);
|
|
248 if (m != NULL) {
|
|
249 if (!strcmp(expansion, m->expansion)) {
|
|
250 complain(p1, "Warning: redefinition of %s", macro);
|
|
251 if (mode.werror) {
|
|
252 complain_fail();
|
|
253 }
|
|
254 return;
|
|
255 }
|
|
256 complain(p1, "Redefinition of %s is not identical", macro);
|
|
257 complain_fail();
|
|
258 return;
|
|
259 }
|
|
260
|
|
261 m = macro_create(p1, p2, hashfunc(macro), macro, expansion);
|
|
262 macrotable_add(m);
|
|
263 }
|
|
264
|
|
265 void
|
|
266 macro_undef(const char *macro)
|
|
267 {
|
|
268 struct macro *m;
|
|
269
|
|
270 m = macrotable_find(macro, true);
|
|
271 if (m) {
|
|
272 macro_destroy(m);
|
|
273 }
|
|
274 }
|
|
275
|
|
276 bool
|
|
277 macro_isdefined(const char *macro)
|
|
278 {
|
|
279 struct macro *m;
|
|
280
|
|
281 m = macrotable_find(macro, false);
|
|
282 return m != NULL;
|
|
283 }
|
|
284
|
|
285 ////////////////////////////////////////////////////////////
|
|
286 // macro expansion
|
|
287
|
|
288 char *macroexpand(struct place *, char *buf, size_t len, bool honordefined);
|
|
289
|
|
290 void macro_sendline(struct place *, char *buf, size_t len);
|
|
291 void macro_sendeof(struct place *);
|
|
292
|
|
293 ////////////////////////////////////////////////////////////
|
|
294 // module initialization
|
|
295
|
|
296 void
|
|
297 macros_init(void)
|
|
298 {
|
|
299 macrotable_init();
|
|
300 }
|
|
301
|
|
302 void
|
|
303 macros_cleanup(void)
|
|
304 {
|
|
305 macrotable_cleanup();
|
|
306 }
|