18 |
02111-1307 USA |
02111-1307 USA |
19 |
*/ |
*/ |
20 |
|
|
|
#include "m4private.h" |
|
|
|
|
|
#define DEBUG_SYM /* Define this to see runtime debug info. */ |
|
|
#undef DEBUG_SYM |
|
|
|
|
21 |
/* 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 |
22 |
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 |
23 |
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 |
27 |
simply ordered on the stack by age. The most recently pushed definition |
simply ordered on the stack by age. The most recently pushed definition |
28 |
will then always be the first found. */ |
will then always be the first found. */ |
29 |
|
|
30 |
|
#include "m4private.h" |
31 |
|
|
32 |
static size_t m4_symtab_hash (const void *key); |
static size_t m4_symtab_hash (const void *key); |
33 |
static int m4_symtab_cmp (const void *key, const void *try); |
static int m4_symtab_cmp (const void *key, const void *try); |
34 |
static void m4_token_data_delete (m4_symbol *data); |
static void m4_token_data_delete (m4_token_data *data); |
35 |
static void m4_symbol_pop (m4_symbol **psymbol); |
static void m4_symbol_pop (m4_symbol *symbol); |
36 |
static void m4_symbol_del (m4_symbol **psymbol); |
static void m4_symbol_del (m4_symbol *symbol); |
|
static int m4_symbol_destroy (const char *name, m4_symbol *symbol, |
|
|
void *data); |
|
37 |
|
|
38 |
|
|
39 |
/* Pointer to symbol table. */ |
/* Pointer to symbol table. */ |
47 |
m4_symtab = m4_hash_new (m4_symtab_hash, m4_symtab_cmp); |
m4_symtab = m4_hash_new (m4_symtab_hash, m4_symtab_cmp); |
48 |
} |
} |
49 |
|
|
|
int |
|
|
m4_symbol_destroy (const char *name, m4_symbol *symbol, void *data) |
|
|
{ |
|
|
m4_symbol_delete (name); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
void |
|
|
m4_symtab_exit (void) |
|
|
{ |
|
|
m4_symtab_apply (m4_symbol_destroy, NULL); |
|
|
m4_hash_delete (m4_symtab); |
|
|
m4_hash_exit (); |
|
|
} |
|
|
|
|
50 |
/* Return a hashvalue for a string, from GNU-emacs. */ |
/* Return a hashvalue for a string, from GNU-emacs. */ |
51 |
size_t |
size_t |
52 |
m4_symtab_hash (const void *key) |
m4_symtab_hash (const void *key) |
74 |
|
|
75 |
|
|
76 |
void |
void |
77 |
m4_token_data_delete (m4_symbol *data) |
m4_token_data_delete (m4_token_data *data) |
78 |
{ |
{ |
79 |
assert (data); |
assert (data); |
80 |
assert (M4_SYMBOL_NEXT (data) == 0); |
assert (M4_TOKEN_DATA_NEXT (data) == 0); |
81 |
|
|
82 |
if (M4_SYMBOL_TYPE (data) == M4_TOKEN_TEXT) |
if (M4_TOKEN_DATA_TYPE (data) == M4_TOKEN_TEXT) |
83 |
XFREE (M4_SYMBOL_TEXT (data)); |
XFREE (M4_TOKEN_DATA_TEXT (data)); |
84 |
|
|
85 |
XFREE (data); |
XFREE (data); |
86 |
} |
} |
87 |
|
|
|
|
|
88 |
void |
void |
89 |
m4_symbol_pop (m4_symbol **psymbol) |
m4_symbol_pop (m4_symbol *symbol) |
90 |
{ |
{ |
91 |
m4_symbol *stale; |
m4_token_data *stale; |
92 |
|
|
93 |
assert (psymbol); |
assert (symbol); |
94 |
assert (*psymbol); |
assert (M4_SYMBOL_DATA_NEXT (symbol)); |
95 |
|
|
96 |
stale = *psymbol; |
stale = M4_SYMBOL_DATA (symbol); |
97 |
*psymbol = M4_SYMBOL_NEXT (stale); |
M4_SYMBOL_DATA (symbol) = M4_TOKEN_DATA_NEXT (stale); |
98 |
|
|
99 |
#ifndef NDEBUG |
#ifndef NDEBUG |
100 |
M4_SYMBOL_NEXT (stale) = 0; |
M4_TOKEN_DATA_NEXT (stale) = 0; |
101 |
#endif |
#endif |
102 |
m4_token_data_delete (stale); |
m4_token_data_delete (stale); |
103 |
} |
} |
104 |
|
|
|
|
|
105 |
/* Free all storage associated with a symbol. */ |
/* Free all storage associated with a symbol. */ |
106 |
void |
void |
107 |
m4_symbol_del (m4_symbol **psymbol) |
m4_symbol_del (m4_symbol *symbol) |
108 |
{ |
{ |
109 |
assert (psymbol); |
assert (symbol); |
110 |
assert (*psymbol); |
|
111 |
|
while (M4_SYMBOL_DATA_NEXT (symbol)) |
112 |
|
m4_symbol_pop (symbol); |
113 |
|
|
114 |
|
assert (M4_SYMBOL_DATA_NEXT (symbol) == 0); |
115 |
|
|
116 |
|
if (M4_SYMBOL_TYPE (symbol) == M4_TOKEN_TEXT) |
117 |
|
XFREE (M4_SYMBOL_TEXT (symbol)); |
118 |
|
|
119 |
while (*psymbol) |
XFREE (M4_SYMBOL_DATA (symbol)); |
120 |
m4_symbol_pop (psymbol); |
XFREE (symbol); |
121 |
} |
} |
122 |
|
|
123 |
|
|
142 |
/* 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 |
143 |
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 |
144 |
this symbol. */ |
this symbol. */ |
145 |
m4_symbol *symbol = XCALLOC (m4_symbol, 1);; |
m4_symbol *symbol = 0; |
146 |
M4_SYMBOL_TYPE (symbol) = M4_TOKEN_VOID; |
m4_token_data *value = XCALLOC (m4_token_data, 1); |
147 |
|
|
148 |
if (psymbol) |
if (psymbol) |
149 |
{ |
{ |
150 |
M4_SYMBOL_NEXT (symbol) = *psymbol; |
symbol = *psymbol; |
151 |
*psymbol = symbol; |
M4_TOKEN_DATA_NEXT (value) = M4_SYMBOL_DATA (symbol); |
152 |
} |
} |
153 |
else |
else |
154 |
|
symbol = XCALLOC (m4_symbol, 1); |
155 |
|
|
156 |
|
M4_SYMBOL_DATA (symbol) = value; |
157 |
|
M4_SYMBOL_TYPE (symbol) = M4_TOKEN_VOID; |
158 |
|
|
159 |
|
if (!psymbol) |
160 |
m4_hash_insert (m4_symtab, xstrdup (name), symbol); |
m4_hash_insert (m4_symtab, xstrdup (name), symbol); |
161 |
|
|
162 |
return symbol; |
return symbol; |
167 |
m4_symbol * |
m4_symbol * |
168 |
m4_symbol_define (const char *name) |
m4_symbol_define (const char *name) |
169 |
{ |
{ |
170 |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup (m4_symtab, name); |
m4_symbol *res = m4_symbol_lookup (name); |
171 |
if (psymbol) |
if (res) |
172 |
return *psymbol; |
return res; |
173 |
else |
else |
174 |
return m4_symbol_pushdef (name); |
m4_symbol_pushdef (name); |
175 |
} |
} |
176 |
|
|
177 |
|
|
183 |
|
|
184 |
assert (psymbol); |
assert (psymbol); |
185 |
|
|
186 |
if (M4_SYMBOL_NEXT (*psymbol)) |
if (M4_SYMBOL_DATA_NEXT (*psymbol)) |
187 |
m4_symbol_pop (psymbol); |
m4_symbol_pop (*psymbol); |
188 |
else |
else |
189 |
{ |
{ |
190 |
xfree (m4_hash_remove (m4_symtab, name)); |
xfree (m4_hash_remove (m4_symtab, name)); |
191 |
m4_symbol_del (psymbol); |
m4_symbol_del (*psymbol); |
192 |
} |
} |
193 |
} |
} |
194 |
|
|
200 |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup (m4_symtab, name); |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup (m4_symtab, name); |
201 |
|
|
202 |
assert (psymbol); |
assert (psymbol); |
|
|
|
|
#ifdef DEBUG_SYM |
|
|
M4_DEBUG_MESSAGE1("symbol %s recycled.", name); |
|
|
#endif |
|
|
|
|
203 |
xfree (m4_hash_remove (m4_symtab, name)); |
xfree (m4_hash_remove (m4_symtab, name)); |
204 |
m4_symbol_del (psymbol); |
m4_symbol_del (*psymbol); |
205 |
} |
} |
206 |
|
|
207 |
|
|
253 |
|
|
254 |
assert (handle); |
assert (handle); |
255 |
|
|
|
/* Traverse each symbol name in the hash table. */ |
|
256 |
while ((place = m4_hash_iterator_next (m4_symtab, place))) |
while ((place = m4_hash_iterator_next (m4_symtab, place))) |
257 |
{ |
{ |
258 |
m4_symbol **psymbol = (m4_symbol **) m4_hash_iterator_value (place); |
m4_symbol *symbol = (m4_symbol *) m4_hash_iterator_value (place); |
259 |
m4_symbol *current = *psymbol; |
m4_token_data *data = M4_SYMBOL_DATA (symbol); |
260 |
|
|
261 |
/* Examine each value in the value stack associated with this |
/* Purge any shadowed references. */ |
262 |
symbol name. */ |
while (M4_TOKEN_DATA_NEXT (data)) |
|
while (M4_SYMBOL_NEXT (current)) |
|
263 |
{ |
{ |
264 |
m4_symbol *next = M4_SYMBOL_NEXT (current); |
m4_token_data *next = M4_TOKEN_DATA_NEXT (data); |
265 |
|
|
266 |
if (M4_SYMBOL_HANDLE (next) == handle) |
if (M4_TOKEN_DATA_HANDLE (next) == handle) |
267 |
{ |
{ |
268 |
M4_SYMBOL_NEXT (current) = M4_SYMBOL_NEXT (next); |
M4_TOKEN_DATA_NEXT (data) = M4_TOKEN_DATA_NEXT (next); |
269 |
m4_token_data_delete (next); |
m4_token_data_delete (next); |
270 |
} |
} |
271 |
else |
else |
272 |
current = next; |
data = next; |
273 |
} |
} |
274 |
|
|
275 |
/* Purge live reference. |
/* Purge live reference. */ |
276 |
This must be performed after the shadowed values have been weeded |
if (M4_SYMBOL_HANDLE (symbol) == handle) |
|
so that the symbol key can be removed from the hash table if this |
|
|
last value matches too. */ |
|
|
if (M4_SYMBOL_HANDLE (*psymbol) == handle) |
|
277 |
{ |
{ |
278 |
if (!M4_SYMBOL_NEXT (*psymbol)) |
if (M4_SYMBOL_DATA_NEXT (symbol)) |
279 |
xfree (m4_hash_remove (m4_symtab, m4_hash_iterator_key (place))); |
m4_symbol_pop (symbol); |
280 |
m4_symbol_pop (psymbol); |
else |
281 |
|
{ |
282 |
|
xfree (m4_hash_remove (m4_symtab, m4_hash_iterator_key (place))); |
283 |
|
m4_symbol_del (symbol); |
284 |
|
} |
285 |
} |
} |
286 |
} |
} |
287 |
} |
} |
288 |
|
|
289 |
/* 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 |
290 |
something to each and every symbol in the table. The function |
something to each and every symbol in the table. The function |
291 |
m4_symtab_apply () traverses the symbol table, and calls a specified |
hack_all_symbols () traverses the symbol table, and calls a specified |
292 |
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 |
293 |
pointer to the symbol, and the DATA argument. */ |
pointer to the symbol, and the DATA argument. */ |
294 |
int |
int |
301 |
|
|
302 |
while ((place = m4_hash_iterator_next (m4_symtab, place))) |
while ((place = m4_hash_iterator_next (m4_symtab, place))) |
303 |
{ |
{ |
304 |
const char *name = (const char *) m4_hash_iterator_key (place); |
const char *name = (const char *) m4_hash_iterator_key (place); |
305 |
m4_symbol **psymbol = (m4_symbol **) m4_hash_iterator_value (place); |
m4_symbol *symbol = (m4_symbol *) m4_hash_iterator_value (place); |
306 |
result = (*func) (name, *psymbol, data); |
result = (*func) (name, symbol, data); |
307 |
|
|
308 |
if (result != 0) |
if (result != 0) |
309 |
break; |
break; |
321 |
static void |
static void |
322 |
symtab_debug (void) |
symtab_debug (void) |
323 |
{ |
{ |
324 |
m4_token_t t; |
m4_token_data_t t; |
325 |
m4_symbol tokenbuf; |
m4_token_data td; |
326 |
const char *text; |
const char *text; |
327 |
m4_symbol *s; |
m4_symbol *s; |
328 |
int delete; |
int delete; |
329 |
|
|
330 |
while ((t = m4_next_token (&tokenbuf)) != M4_TOKEN_EOF) |
while ((t = m4_next_token (&td)) != NULL) |
331 |
{ |
{ |
332 |
if (t != M4_TOKEN_WORD) |
if (t != M4_TOKEN_WORD) |
333 |
continue; |
continue; |
334 |
text = M4_SYMBOL_TEXT (&tokenbuf); |
text = M4_TOKEN_DATA_TEXT (&td); |
335 |
if (*text == '_') |
if (*text == '_') |
336 |
{ |
{ |
337 |
delete = 1; |
delete = 1; |