42 |
of fluff in these functions to make sure that such symbols (with empty |
of fluff in these functions to make sure that such symbols (with empty |
43 |
value stacks) are invisible to the users of this module. */ |
value stacks) are invisible to the users of this module. */ |
44 |
|
|
45 |
#define M4_SYMTAB_DEFAULT_SIZE 2047 |
#define M4_SYMTAB_DEFAULT_SIZE 2047 |
46 |
|
#define M4_ARG_SIGNATURE_DEFAULT_SIZE 7 |
47 |
|
|
48 |
static int symbol_destroy (m4_hash *hash, const void *name, |
static m4_symbol *symtab_fetch (m4_symtab*, const char *); |
49 |
|
static void symbol_popval (m4_symbol *symbol); |
50 |
|
static int symbol_destroy (m4_hash *hash, const void *name, |
51 |
void *symbol, void *ignored); |
void *symbol, void *ignored); |
52 |
static int arg_destroy (m4_hash *hash, const void *name, |
static int arg_destroy (m4_hash *hash, const void *name, |
53 |
void *arg, void *ignored); |
void *arg, void *ignored); |
54 |
|
static m4_hash * arg_signature_parse (const char *name, const char *param); |
55 |
|
|
56 |
|
|
57 |
|
|
75 |
m4_hash_delete ((m4_hash *) symtab); |
m4_hash_delete ((m4_hash *) symtab); |
76 |
} |
} |
77 |
|
|
78 |
|
static m4_symbol * |
79 |
|
symtab_fetch (m4_symtab *symtab, const char *name) |
80 |
|
{ |
81 |
|
m4_symbol **psymbol; |
82 |
|
m4_symbol *symbol; |
83 |
|
|
84 |
|
assert (symtab); |
85 |
|
assert (name); |
86 |
|
|
87 |
|
psymbol = (m4_symbol **) m4_hash_lookup ((m4_hash *) symtab, name); |
88 |
|
if (psymbol) |
89 |
|
{ |
90 |
|
symbol = *psymbol; |
91 |
|
} |
92 |
|
else |
93 |
|
{ |
94 |
|
symbol = XCALLOC (m4_symbol, 1); |
95 |
|
m4_hash_insert ((m4_hash *) symtab, xstrdup (name), symbol); |
96 |
|
} |
97 |
|
|
98 |
|
return symbol; |
99 |
|
} |
100 |
|
|
101 |
/* Remove every symbol that references the given module handle from |
/* Remove every symbol that references the given module handle from |
102 |
the symbol table. */ |
the symbol table. */ |
181 |
|
|
182 |
|
|
183 |
/* Insert NAME into the symbol table. If there is already a symbol |
/* Insert NAME into the symbol table. If there is already a symbol |
184 |
associated with NAME, push the new value on top of the value stack |
associated with NAME, push the new VALUE on top of the value stack |
185 |
for this symbol. Otherwise create a new association. */ |
for this symbol. Otherwise create a new association. */ |
186 |
m4_symbol * |
m4_symbol * |
187 |
m4_symbol_pushdef (m4_symtab *symtab, const char *name) |
m4_symbol_pushdef (m4_symtab *symtab, const char *name, m4_token *value) |
188 |
{ |
{ |
189 |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup ((m4_hash *) symtab, |
m4_symbol *symbol; |
|
name); |
|
|
|
|
|
m4_symbol *symbol = 0; |
|
|
m4_token *value = XCALLOC (m4_token, 1); |
|
190 |
|
|
191 |
if (psymbol) |
assert (symtab); |
192 |
{ |
assert (name); |
193 |
symbol = *psymbol; |
assert (value); |
|
TOKEN_NEXT (value) = SYMBOL_TOKEN (symbol); |
|
|
} |
|
|
else |
|
|
symbol = XCALLOC (m4_symbol, 1); |
|
194 |
|
|
195 |
|
symbol = symtab_fetch (symtab, name); |
196 |
|
TOKEN_NEXT (value) = SYMBOL_TOKEN (symbol); |
197 |
SYMBOL_TOKEN (symbol) = value; |
SYMBOL_TOKEN (symbol) = value; |
|
SYMBOL_TYPE (symbol) = M4_TOKEN_VOID; |
|
198 |
|
|
199 |
if (!psymbol) |
assert (SYMBOL_TOKEN (symbol)); |
|
m4_hash_insert ((m4_hash *) symtab, xstrdup (name), symbol); |
|
200 |
|
|
201 |
return symbol; |
return symbol; |
202 |
} |
} |
203 |
|
|
|
|
|
204 |
/* Return the symbol associated with NAME in the symbol table, creating |
/* Return the symbol associated with NAME in the symbol table, creating |
205 |
a new symbol if necessary. */ |
a new symbol if necessary. In either case set the symbol's VALUE. */ |
206 |
m4_symbol * |
m4_symbol * |
207 |
m4_symbol_define (m4_symtab *symtab, const char *name) |
m4_symbol_define (m4_symtab *symtab, const char *name, m4_token *value) |
208 |
{ |
{ |
209 |
m4_symbol *symbol = m4_symbol_lookup (symtab, name); |
m4_symbol *symbol; |
210 |
|
|
211 |
if (symbol) |
assert (symtab); |
212 |
return symbol; |
assert (name); |
213 |
|
assert (value); |
214 |
|
|
215 |
return m4_symbol_pushdef (symtab, name); |
symbol = symtab_fetch (symtab, name); |
216 |
|
if (SYMBOL_TOKEN (symbol)) |
217 |
|
symbol_popval (symbol); |
218 |
|
|
219 |
|
TOKEN_NEXT (value) = SYMBOL_TOKEN (symbol); |
220 |
|
SYMBOL_TOKEN (symbol) = value; |
221 |
|
|
222 |
|
assert (SYMBOL_TOKEN (symbol)); |
223 |
|
|
224 |
|
return symbol; |
225 |
|
} |
226 |
|
|
227 |
|
void |
228 |
|
m4_set_symbol_traced (m4_symtab *symtab, const char *name) |
229 |
|
{ |
230 |
|
m4_symbol *symbol; |
231 |
|
|
232 |
|
assert (symtab); |
233 |
|
assert (name); |
234 |
|
|
235 |
|
symbol = symtab_fetch (symtab, name); |
236 |
|
|
237 |
|
SYMBOL_TRACED (symbol) = TRUE; |
238 |
} |
} |
239 |
|
|
240 |
|
|
246 |
{ |
{ |
247 |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup ((m4_hash *) symtab, |
m4_symbol **psymbol = (m4_symbol **) m4_hash_lookup ((m4_hash *) symtab, |
248 |
name); |
name); |
|
m4_token *stale = NULL; |
|
|
|
|
249 |
assert (psymbol); |
assert (psymbol); |
250 |
assert (*psymbol); |
assert (*psymbol); |
251 |
|
|
252 |
stale = SYMBOL_TOKEN (*psymbol); |
symbol_popval (*psymbol); |
253 |
|
|
254 |
|
/* Only remove the hash table entry if the last value in the |
255 |
|
symbol value stack was successfully removed. */ |
256 |
|
if (!SYMBOL_TOKEN (*psymbol)) |
257 |
|
if (no_gnu_extensions || !SYMBOL_TRACED (*psymbol)) |
258 |
|
{ |
259 |
|
XFREE (*psymbol); |
260 |
|
xfree (m4_hash_remove ((m4_hash *) symtab, name)); |
261 |
|
} |
262 |
|
} |
263 |
|
|
264 |
|
|
265 |
|
static void |
266 |
|
symbol_popval (m4_symbol *symbol) |
267 |
|
{ |
268 |
|
m4_token *stale; |
269 |
|
|
270 |
|
assert (symbol); |
271 |
|
|
272 |
|
stale = SYMBOL_TOKEN (symbol); |
273 |
|
|
274 |
if (stale) |
if (stale) |
275 |
{ |
{ |
276 |
SYMBOL_TOKEN (*psymbol) = TOKEN_NEXT (stale); |
SYMBOL_TOKEN (symbol) = TOKEN_NEXT (stale); |
277 |
|
|
278 |
if (TOKEN_ARG_SIGNATURE (stale)) |
if (TOKEN_ARG_SIGNATURE (stale)) |
279 |
{ |
{ |
284 |
XFREE (TOKEN_TEXT (stale)); |
XFREE (TOKEN_TEXT (stale)); |
285 |
XFREE (stale); |
XFREE (stale); |
286 |
} |
} |
|
|
|
|
/* Only remove the hash table entry if the last value in the |
|
|
symbol value stack was successfully removed. */ |
|
|
if (!SYMBOL_TOKEN (*psymbol)) |
|
|
if (no_gnu_extensions || !SYMBOL_TRACED (*psymbol)) |
|
|
{ |
|
|
XFREE (*psymbol); |
|
|
xfree (m4_hash_remove ((m4_hash *) symtab, name)); |
|
|
} |
|
287 |
} |
} |
288 |
|
|
|
|
|
289 |
/* Callback used by m4_symbol_popdef () to release the memory used |
/* Callback used by m4_symbol_popdef () to release the memory used |
290 |
by values in the arg_signature hash. */ |
by values in the arg_signature hash. */ |
291 |
static int |
static int |
304 |
return 0; |
return 0; |
305 |
} |
} |
306 |
|
|
307 |
|
#if 0 |
|
/* Set the type and value of a symbol according to the passed |
|
|
arguments. This function is usually passed a newly pushdef()d symbol |
|
|
that is already interned in the symbol table. The traced bit should |
|
|
be appropriately set by the caller. */ |
|
308 |
m4_symbol * |
m4_symbol * |
309 |
m4__symbol_set_builtin (m4_symbol *symbol, m4_token *token) |
m4_symbol_push_token (m4_symtab *symtab, const char *name, m4_token *token) |
310 |
{ |
{ |
311 |
assert (symbol); |
m4_token *next; |
312 |
|
|
313 |
|
assert (symtab); |
314 |
|
assert (name); |
315 |
assert (token); |
assert (token); |
316 |
assert (TOKEN_FUNC (token)); |
|
317 |
assert (TOKEN_HANDLE (token)); |
/* If it's a function, it must have come from a module. */ |
318 |
assert (TOKEN_TYPE (token) == M4_TOKEN_FUNC); |
assert ((TOKEN_TYPE (token) != M4_TOKEN_FUNC) || TOKEN_HANDLE (token)); |
319 |
|
|
320 |
if (SYMBOL_TYPE (symbol) == M4_TOKEN_TEXT) |
#if M4PARAMS |
321 |
xfree (SYMBOL_TEXT (symbol)); |
const char *openp = NULL; |
322 |
|
const char *params = NULL; |
323 |
SYMBOL_TYPE (symbol) = TOKEN_TYPE (token); |
|
324 |
SYMBOL_FUNC (symbol) = TOKEN_FUNC (token); |
if (!no_gnu_extensions) |
325 |
SYMBOL_HANDLE (symbol) = TOKEN_HANDLE (token); |
{ |
326 |
SYMBOL_FLAGS (symbol) = TOKEN_FLAGS (token); |
/* If name contains an open paren, then parse before that paren |
327 |
SYMBOL_ARG_SIGNATURE (symbol) = TOKEN_ARG_SIGNATURE (token); |
as the actual name, and the rest as a formal parameter list. */ |
328 |
SYMBOL_MIN_ARGS (symbol) = TOKEN_MIN_ARGS (token); |
size_t len = 0; |
329 |
SYMBOL_MAX_ARGS (symbol) = TOKEN_MAX_ARGS (token); |
for (openp = name; *openp && !M4_IS_OPEN (*openp); ++openp) |
330 |
|
++len; |
331 |
|
|
332 |
|
if (*openp) |
333 |
|
{ |
334 |
|
name = xstrzdup (name, len); |
335 |
|
params = 1+ openp; |
336 |
|
} |
337 |
|
} |
338 |
|
|
339 |
|
if (params) |
340 |
|
{ |
341 |
|
/* Make a hash table to map formal parameter names to |
342 |
|
argv offsets, and store that in the symbol's token. */ |
343 |
|
TOKEN_ARG_SIGNATURE (token) = arg_signature_parse (name, params); |
344 |
|
} |
345 |
|
#endif |
346 |
|
|
347 |
|
SYMBOL_TOKEN (symbol) = token; |
348 |
|
|
349 |
|
#if M4PARAMS |
350 |
|
/* If we split name on open paren, free the copied substring. */ |
351 |
|
if (params) |
352 |
|
xfree ((char *) name); |
353 |
|
#endif |
354 |
|
|
355 |
return symbol; |
return symbol; |
356 |
} |
} |
357 |
|
#endif |
358 |
|
|
359 |
/* ...and similarly for macro valued symbols. */ |
void |
360 |
m4_symbol * |
m4_token_copy (m4_token *dest, m4_token *src) |
|
m4__symbol_set_macro (m4_symbol *symbol, m4_token *token) |
|
361 |
{ |
{ |
362 |
assert (symbol); |
m4_token *next; |
|
assert (TOKEN_TEXT (token)); |
|
|
assert (TOKEN_TYPE (token) == M4_TOKEN_TEXT); |
|
363 |
|
|
364 |
if (SYMBOL_TYPE (symbol) == M4_TOKEN_TEXT) |
assert (dest); |
365 |
xfree (SYMBOL_TEXT (symbol)); |
assert (src); |
366 |
|
|
367 |
SYMBOL_TYPE (symbol) = TOKEN_TYPE (token); |
if (TOKEN_TYPE (dest) == M4_TOKEN_TEXT) |
368 |
SYMBOL_TEXT (symbol) = xstrdup (TOKEN_TEXT (token)); |
xfree (TOKEN_TEXT (dest)); |
|
SYMBOL_HANDLE (symbol) = TOKEN_HANDLE (token); |
|
|
SYMBOL_FLAGS (symbol) = TOKEN_FLAGS (token); |
|
|
SYMBOL_ARG_SIGNATURE (symbol) = TOKEN_ARG_SIGNATURE (token); |
|
|
SYMBOL_MIN_ARGS (symbol) = TOKEN_MIN_ARGS (token); |
|
|
SYMBOL_MAX_ARGS (symbol) = TOKEN_MAX_ARGS (token); |
|
369 |
|
|
370 |
return symbol; |
#if M4PARAMS |
371 |
|
if (TOKEN_ARG_SIGNATURE (dest)) |
372 |
|
{ |
373 |
|
m4_hash_apply (TOKEN_ARG_SIGNATURE (dest), arg_destroy, NULL); |
374 |
|
m4_hash_delete (TOKEN_ARG_SIGNATURE (dest)); |
375 |
|
} |
376 |
|
#endif |
377 |
|
|
378 |
|
/* Copy the token contents over, being careful to preserve |
379 |
|
the next pointer. */ |
380 |
|
next = TOKEN_NEXT (dest); |
381 |
|
bcopy (src, dest, sizeof (m4_token)); |
382 |
|
TOKEN_NEXT (dest) = next; |
383 |
|
|
384 |
|
/* Caller is supposed to free text token strings, so we have to |
385 |
|
copy the string not just its address in that case. */ |
386 |
|
if (TOKEN_TYPE (src) == M4_TOKEN_TEXT) |
387 |
|
TOKEN_TEXT (dest) = xstrdup (TOKEN_TEXT (src)); |
388 |
|
|
389 |
|
#if M4PARAMS |
390 |
|
if (TOKEN_ARG_SIGNATURE (src)) |
391 |
|
TOKEN_ARG_SIGNATURE (dest) = m4_hash_dup (TOKEN_ARG_SIGNATURE (token)); |
392 |
|
#endif |
393 |
} |
} |
394 |
|
|
395 |
|
#if M4PARAMS |
396 |
|
static m4_hash * |
397 |
|
arg_signature_parse (const char *name, const char *params) |
398 |
|
{ |
399 |
|
m4_hash *arg_signature; |
400 |
|
const char *commap; |
401 |
|
int offset; |
402 |
|
|
403 |
|
assert (params); |
404 |
|
|
405 |
|
arg_signature = m4_hash_new (M4_ARG_SIGNATURE_DEFAULT_SIZE, |
406 |
|
m4_hash_string_hash, m4_hash_string_cmp); |
407 |
|
|
408 |
|
for (offset = 1; *params && !M4_IS_CLOSE (*params); ++offset) |
409 |
|
{ |
410 |
|
size_t len = 0; |
411 |
|
|
412 |
|
/* Skip leading whitespace. */ |
413 |
|
while (M4_IS_SPACE (*params)) |
414 |
|
++params; |
415 |
|
|
416 |
|
for (commap = params; *commap && M4_IS_IDENT (*commap); ++commap) |
417 |
|
++len; |
418 |
|
|
419 |
|
/* Skip trailing whitespace. */ |
420 |
|
while (M4_IS_SPACE (*commap)) |
421 |
|
++commap; |
422 |
|
|
423 |
|
if (!M4_IS_COMMA (*commap) && !M4_IS_CLOSE (*commap)) |
424 |
|
M4ERROR ((EXIT_FAILURE, 0, |
425 |
|
_("Error: %s: syntax error in parameter list at char `%c'"), |
426 |
|
name, *commap)); |
427 |
|
|
428 |
|
/* Skip parameter delimiter. */ |
429 |
|
if (M4_IS_COMMA (*commap)) |
430 |
|
++commap; |
431 |
|
|
432 |
|
if (len) |
433 |
|
{ |
434 |
|
struct m4_token_arg *arg = XCALLOC (struct m4_token_arg, 1); |
435 |
|
|
436 |
|
TOKEN_ARG_INDEX (arg) = offset; |
437 |
|
|
438 |
|
m4_hash_insert (arg_signature, xstrzdup (params, len), arg); |
439 |
|
|
440 |
|
params = commap; |
441 |
|
} |
442 |
|
} |
443 |
|
|
444 |
|
if (!M4_IS_CLOSE (*commap)) |
445 |
|
M4WARN ((warning_status, 0, |
446 |
|
_("Warning: %s: unterminated parameter list"), name)); |
447 |
|
|
448 |
|
return arg_signature; |
449 |
|
} |
450 |
|
#endif |
451 |
|
|
452 |
|
|
453 |
|
|
454 |
#ifdef DEBUG_SYM |
#ifdef DEBUG_SYM |
455 |
|
|
456 |
static int symtab_print_list (const void *name, void *symbol, void *ignored); |
static int symtab_print_list (m4_hash *hash, const void *name, void *symbol, |
457 |
static void symtab_debug (void) |
void *ignored); |
458 |
static void symtab_dump (void); |
static void symtab_debug (m4_symtab *symtab); |
459 |
|
static void symtab_dump (m4_symtab *symtab); |
460 |
|
|
461 |
static void |
static void |
462 |
symtab_dump (void) |
symtab_dump (m4_symtab *symtab) |
463 |
{ |
{ |
464 |
m4_hash_iterator *place = 0; |
m4_hash_iterator *place = 0; |
465 |
|
|
528 |
printf (_("Name `%s' is unknown\n"), text); |
printf (_("Name `%s' is unknown\n"), text); |
529 |
|
|
530 |
if (delete) |
if (delete) |
531 |
(void) m4_symbol_delete (symtab, text); |
m4_symbol_delete (symtab, text); |
532 |
else |
else |
533 |
(void) m4_symbol_define (symtab, text); |
symtab_fetch (symtab, text); |
534 |
} |
} |
535 |
m4_symtab_apply (symtab, symtab_print_list, NULL); |
m4_symtab_apply (symtab, symtab_print_list, NULL); |
536 |
} |
} |