18 |
02111-1307 USA |
02111-1307 USA |
19 |
*/ |
*/ |
20 |
|
|
21 |
|
#include "m4private.h" |
22 |
|
|
23 |
|
#define DEBUG_SYM /* Define this to see runtime debug info. */ |
24 |
|
#undef DEBUG_SYM |
25 |
|
|
26 |
/* This file handles all the low level work around the symbol table. The |
/* This file handles all the low level work around the symbol table. The |
27 |
symbol table is an abstract hash table type implemented in hash.c. Each |
symbol table is an abstract hash table type implemented in hash.c. Each |
28 |
symbol is represented by `struct m4_symbol', which is stored in the hash |
symbol is represented by `struct m4_symbol', which is stored in the hash |
32 |
simply ordered on the stack by age. The most recently pushed definition |
simply ordered on the stack by age. The most recently pushed definition |
33 |
will then always be the first found. */ |
will then always be the first found. */ |
34 |
|
|
|
#include "m4private.h" |
|
|
|
|
35 |
static size_t m4_symtab_hash (const void *key); |
static size_t m4_symtab_hash (const void *key); |
36 |
static int m4_symtab_cmp (const void *key, const void *try); |
static int m4_symtab_cmp (const void *key, const void *try); |
37 |
static void m4_token_data_delete (m4_token_data *data); |
static void m4_token_data_delete (m4_symbol *data); |
38 |
static void m4_symbol_pop (m4_symbol *symbol); |
static void m4_symbol_pop (m4_symbol **psymbol); |
39 |
static void m4_symbol_del (m4_symbol *symbol); |
static void m4_symbol_del (m4_symbol **psymbol); |
40 |
|
static int m4_symbol_destroy (const char *name, m4_symbol *symbol, |
41 |
|
void *data); |
42 |
|
|
43 |
|
|
44 |
/* Pointer to symbol table. */ |
/* Pointer to symbol table. */ |
52 |
m4_symtab = m4_hash_new (m4_symtab_hash, m4_symtab_cmp); |
m4_symtab = m4_hash_new (m4_symtab_hash, m4_symtab_cmp); |
53 |
} |
} |
54 |
|
|
55 |
|
int |
56 |
|
m4_symbol_destroy (const char *name, m4_symbol *symbol, void *data) |
57 |
|
{ |
58 |
|
m4_symbol_delete (name); |
59 |
|
return 0; |
60 |
|
} |
61 |
|
|
62 |
|
void |
63 |
|
m4_symtab_exit (void) |
64 |
|
{ |
65 |
|
m4_symtab_apply (m4_symbol_destroy, NULL); |
66 |
|
m4_hash_delete (m4_symtab); |
67 |
|
m4_hash_exit (); |
68 |
|
} |
69 |
|
|
70 |
/* Return a hashvalue for a string, from GNU-emacs. */ |
/* Return a hashvalue for a string, from GNU-emacs. */ |
71 |
size_t |
size_t |
72 |
m4_symtab_hash (const void *key) |
m4_symtab_hash (const void *key) |
94 |
|
|
95 |
|
|
96 |
void |
void |
97 |
m4_token_data_delete (m4_token_data *data) |
m4_token_data_delete (m4_symbol *data) |
98 |
{ |
{ |
99 |
assert (data); |
assert (data); |
100 |
assert (M4_TOKEN_DATA_NEXT (data) == 0); |
assert (M4_SYMBOL_NEXT (data) == 0); |
101 |
|
|
102 |
if (M4_TOKEN_DATA_TYPE (data) == M4_TOKEN_TEXT) |
if (M4_SYMBOL_TYPE (data) == M4_TOKEN_TEXT) |
103 |
XFREE (M4_TOKEN_DATA_TEXT (data)); |
XFREE (M4_SYMBOL_TEXT (data)); |
104 |
|
|
105 |
XFREE (data); |
XFREE (data); |
106 |
} |
} |
107 |
|
|
108 |
|
|
109 |
void |
void |
110 |
m4_symbol_pop (m4_symbol *symbol) |
m4_symbol_pop (m4_symbol **psymbol) |
111 |
{ |
{ |
112 |
m4_token_data *stale; |
m4_symbol *stale; |
113 |
|
|
114 |
assert (symbol); |
assert (psymbol); |
115 |
assert (M4_SYMBOL_DATA_NEXT (symbol)); |
assert (*psymbol); |
116 |
|
|
117 |
stale = M4_SYMBOL_DATA (symbol); |
stale = *psymbol; |
118 |
M4_SYMBOL_DATA (symbol) = M4_TOKEN_DATA_NEXT (stale); |
*psymbol = M4_SYMBOL_NEXT (stale); |
119 |
|
|
120 |
#ifndef NDEBUG |
#ifndef NDEBUG |
121 |
M4_TOKEN_DATA_NEXT (stale) = 0; |
M4_SYMBOL_NEXT (stale) = 0; |
122 |
#endif |
#endif |
123 |
m4_token_data_delete (stale); |
m4_token_data_delete (stale); |
124 |
} |
} |
125 |
|
|
126 |
|
|
127 |
/* Free all storage associated with a symbol. */ |
/* Free all storage associated with a symbol. */ |
128 |
void |
void |
129 |
m4_symbol_del (m4_symbol *symbol) |
m4_symbol_del (m4_symbol **psymbol) |
130 |
{ |
{ |
131 |
assert (symbol); |
assert (psymbol); |
132 |
|
assert (*psymbol); |
|
while (M4_SYMBOL_DATA_NEXT (symbol)) |
|
|
m4_symbol_pop (symbol); |
|
|
|
|
|
assert (M4_SYMBOL_DATA_NEXT (symbol) == 0); |
|
|
|
|
|
if (M4_SYMBOL_TYPE (symbol) == M4_TOKEN_TEXT) |
|
|
XFREE (M4_SYMBOL_TEXT (symbol)); |
|
133 |
|
|
134 |
XFREE (M4_SYMBOL_DATA (symbol)); |
while (*psymbol) |
135 |
XFREE (symbol); |
m4_symbol_pop (psymbol); |
136 |
} |
} |
137 |
|
|
138 |
|
|
157 |
/* Insert a name in the symbol table. If there is already a symbol |
/* Insert a name in the symbol table. If there is already a symbol |
158 |
with the name, push the new value on top of the value stack for |
with the name, push the new value on top of the value stack for |
159 |
this symbol. */ |
this symbol. */ |
160 |
m4_symbol *symbol = 0; |
m4_symbol *symbol = XCALLOC (m4_symbol, 1);; |
161 |
m4_token_data *value = XCALLOC (m4_token_data, 1); |
M4_SYMBOL_TYPE (symbol) = M4_TOKEN_VOID; |
162 |
|
|
163 |
if (psymbol) |
if (psymbol) |
164 |
{ |
{ |
165 |
symbol = *psymbol; |
M4_SYMBOL_NEXT (symbol) = *psymbol; |
166 |
M4_TOKEN_DATA_NEXT (value) = M4_SYMBOL_DATA (symbol); |
*psymbol = symbol; |
167 |
} |
} |
168 |
else |
else |
|
symbol = XCALLOC (m4_symbol, 1); |
|
|
|
|
|
M4_SYMBOL_DATA (symbol) = value; |
|
|
M4_SYMBOL_TYPE (symbol) = M4_TOKEN_VOID; |
|
|
|
|
|
if (!psymbol) |
|
169 |
m4_hash_insert (m4_symtab, xstrdup (name), symbol); |
m4_hash_insert (m4_symtab, xstrdup (name), symbol); |
170 |
|
|
171 |
return symbol; |
return symbol; |
176 |
m4_symbol * |
m4_symbol * |
177 |
m4_symbol_define (const char *name) |
m4_symbol_define (const char *name) |
178 |
{ |
{ |
179 |
m4_symbol *res = m4_symbol_lookup (name); |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup (m4_symtab, name); |
180 |
if (res) |
if (psymbol) |
181 |
return res; |
return *psymbol; |
182 |
else |
else |
183 |
m4_symbol_pushdef (name); |
return m4_symbol_pushdef (name); |
184 |
} |
} |
185 |
|
|
186 |
|
|
192 |
|
|
193 |
assert (psymbol); |
assert (psymbol); |
194 |
|
|
195 |
if (M4_SYMBOL_DATA_NEXT (*psymbol)) |
if (M4_SYMBOL_NEXT (*psymbol)) |
196 |
m4_symbol_pop (*psymbol); |
m4_symbol_pop (psymbol); |
197 |
else |
else |
198 |
{ |
{ |
199 |
xfree (m4_hash_remove (m4_symtab, name)); |
xfree (m4_hash_remove (m4_symtab, name)); |
200 |
m4_symbol_del (*psymbol); |
m4_symbol_del (psymbol); |
201 |
} |
} |
202 |
} |
} |
203 |
|
|
209 |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup (m4_symtab, name); |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup (m4_symtab, name); |
210 |
|
|
211 |
assert (psymbol); |
assert (psymbol); |
212 |
|
|
213 |
|
#ifdef DEBUG_SYM |
214 |
|
M4_DEBUG_MESSAGE1("symbol %s recycled.", name); |
215 |
|
#endif |
216 |
|
|
217 |
xfree (m4_hash_remove (m4_symtab, name)); |
xfree (m4_hash_remove (m4_symtab, name)); |
218 |
m4_symbol_del (*psymbol); |
m4_symbol_del (psymbol); |
219 |
} |
} |
220 |
|
|
221 |
|
|
267 |
|
|
268 |
assert (handle); |
assert (handle); |
269 |
|
|
270 |
|
/* Traverse each symbol name in the hash table. */ |
271 |
while ((place = m4_hash_iterator_next (m4_symtab, place))) |
while ((place = m4_hash_iterator_next (m4_symtab, place))) |
272 |
{ |
{ |
273 |
m4_symbol *symbol = (m4_symbol *) m4_hash_iterator_value (place); |
m4_symbol **psymbol = (m4_symbol **) m4_hash_iterator_value (place); |
274 |
m4_token_data *data = M4_SYMBOL_DATA (symbol); |
m4_symbol *current = *psymbol; |
275 |
|
|
276 |
/* Purge any shadowed references. */ |
/* Examine each value in the value stack associated with this |
277 |
while (M4_TOKEN_DATA_NEXT (data)) |
symbol name. */ |
278 |
|
while (M4_SYMBOL_NEXT (current)) |
279 |
{ |
{ |
280 |
m4_token_data *next = M4_TOKEN_DATA_NEXT (data); |
m4_symbol *next = M4_SYMBOL_NEXT (current); |
281 |
|
|
282 |
if (M4_TOKEN_DATA_HANDLE (next) == handle) |
if (M4_SYMBOL_HANDLE (next) == handle) |
283 |
{ |
{ |
284 |
M4_TOKEN_DATA_NEXT (data) = M4_TOKEN_DATA_NEXT (next); |
M4_SYMBOL_NEXT (current) = M4_SYMBOL_NEXT (next); |
285 |
m4_token_data_delete (next); |
m4_token_data_delete (next); |
286 |
} |
} |
287 |
else |
else |
288 |
data = next; |
current = next; |
289 |
} |
} |
290 |
|
|
291 |
/* Purge live reference. */ |
/* Purge live reference. |
292 |
if (M4_SYMBOL_HANDLE (symbol) == handle) |
This must be performed after the shadowed values have been weeded |
293 |
|
so that the symbol key can be removed from the hash table if this |
294 |
|
last value matches too. */ |
295 |
|
if (M4_SYMBOL_HANDLE (*psymbol) == handle) |
296 |
{ |
{ |
297 |
if (M4_SYMBOL_DATA_NEXT (symbol)) |
if (!M4_SYMBOL_NEXT (*psymbol)) |
298 |
m4_symbol_pop (symbol); |
xfree (m4_hash_remove (m4_symtab, m4_hash_iterator_key (place))); |
299 |
else |
m4_symbol_pop (psymbol); |
|
{ |
|
|
xfree (m4_hash_remove (m4_symtab, m4_hash_iterator_key (place))); |
|
|
m4_symbol_del (symbol); |
|
|
} |
|
300 |
} |
} |
301 |
} |
} |
302 |
} |
} |
303 |
|
|
304 |
/* The following function is used for the cases, where we want to do |
/* The following function is used for the cases where we want to do |
305 |
something to each and every symbol in the table. The function |
something to each and every symbol in the table. The function |
306 |
hack_all_symbols () traverses the symbol table, and calls a specified |
m4_symtab_apply () traverses the symbol table, and calls a specified |
307 |
function FUNC for each symbol in the table. FUNC is called with a |
function FUNC for each symbol in the table. FUNC is called with a |
308 |
pointer to the symbol, and the DATA argument. */ |
pointer to the symbol, and the DATA argument. */ |
309 |
int |
int |
316 |
|
|
317 |
while ((place = m4_hash_iterator_next (m4_symtab, place))) |
while ((place = m4_hash_iterator_next (m4_symtab, place))) |
318 |
{ |
{ |
319 |
const char *name = (const char *) m4_hash_iterator_key (place); |
const char *name = (const char *) m4_hash_iterator_key (place); |
320 |
m4_symbol *symbol = (m4_symbol *) m4_hash_iterator_value (place); |
m4_symbol **psymbol = (m4_symbol **) m4_hash_iterator_value (place); |
321 |
result = (*func) (name, symbol, data); |
result = (*func) (name, *psymbol, data); |
322 |
|
|
323 |
if (result != 0) |
if (result != 0) |
324 |
break; |
break; |
336 |
static void |
static void |
337 |
symtab_debug (void) |
symtab_debug (void) |
338 |
{ |
{ |
339 |
m4_token_data_t t; |
m4_token_t t; |
340 |
m4_token_data td; |
m4_symbol tokenbuf; |
341 |
const char *text; |
const char *text; |
342 |
m4_symbol *s; |
m4_symbol *s; |
343 |
int delete; |
int delete; |
344 |
|
|
345 |
while ((t = m4_next_token (&td)) != NULL) |
while ((t = m4_next_token (&tokenbuf)) != M4_TOKEN_EOF) |
346 |
{ |
{ |
347 |
if (t != M4_TOKEN_WORD) |
if (t != M4_TOKEN_WORD) |
348 |
continue; |
continue; |
349 |
text = M4_TOKEN_DATA_TEXT (&td); |
text = M4_SYMBOL_TEXT (&tokenbuf); |
350 |
if (*text == '_') |
if (*text == '_') |
351 |
{ |
{ |
352 |
delete = 1; |
delete = 1; |