diff options
author | Martin Mares <mj@ucw.cz> | 2000-06-04 21:30:13 +0200 |
---|---|---|
committer | Martin Mares <mj@ucw.cz> | 2000-06-04 21:30:13 +0200 |
commit | 04dc62a0116941d2f1510216539ae8c11c5f1cb3 (patch) | |
tree | ead689c0378fa535ecb3ae7dbe9d86f98c043653 | |
parent | dab66519160042f1fb62a285e3a947233ce74e70 (diff) | |
download | bird-04dc62a0116941d2f1510216539ae8c11c5f1cb3.tar bird-04dc62a0116941d2f1510216539ae8c11c5f1cb3.zip |
Nested scopes could never have worked. My fault I wrote such a buggy code,
Pavel's fault that he's never tested shadowing of declarations in the filters.
cf_define_symbol() has been modified to check the scope of the symbol it's
given and it if it's an already defined symbol, but in a different scope,
a copy is created in the current scope and redefined to the new meaning,
the consequence being that it cf_define_symbol() now returns the new symbol
you need to use when assigning aux and aux2.
-rw-r--r-- | conf/cf-lex.l | 59 | ||||
-rw-r--r-- | conf/conf.h | 2 |
2 files changed, 40 insertions, 21 deletions
diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 8f8fcfb..9ded49c 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -213,11 +213,33 @@ cf_hash(byte *c) } static struct symbol * +cf_new_sym(byte *c, unsigned int h) +{ + struct symbol *s, **ht; + int l; + + if (!new_config->sym_hash) + new_config->sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *)); + ht = new_config->sym_hash; + l = strlen(c); + if (l > SYM_MAX_LEN) + cf_error("Symbol too long"); + s = cfg_alloc(sizeof(struct symbol) + l); + s->next = ht[h]; + ht[h] = s; + s->scope = conf_this_scope; + s->class = SYM_VOID; + s->def = NULL; + s->aux = 0; + strcpy(s->name, c); + return s; +} + +static struct symbol * cf_find_sym(byte *c, unsigned int h0) { unsigned int h = h0 & (SYM_HASH_SIZE-1); struct symbol *s, **ht; - int l; if (ht = new_config->sym_hash) { @@ -232,20 +254,7 @@ cf_find_sym(byte *c, unsigned int h0) if (!strcmp(s->name, c) && s->scope->active) return s; } - if (!ht) - ht = new_config->sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *)); - l = strlen(c); - if (l > SYM_MAX_LEN) - cf_error("Symbol too long"); - s = cfg_alloc(sizeof(struct symbol) + l); - s->next = ht[h]; - ht[h] = s; - s->scope = conf_this_scope; - s->class = SYM_VOID; - s->def = NULL; - s->aux = 0; - strcpy(s->name, c); - return s; + return cf_new_sym(c, h); } /** @@ -291,17 +300,27 @@ cf_default_name(char *template, int *counter) * @type: symbol class to assign * @def: class dependent data * - * This function takes a symbol, checks whether it's really - * an undefined one (else it raises an error) and assigns the - * given class and definition to it. + * Defines new meaning of a symbol. If the symbol is an undefined + * one (%SYM_VOID), it's just re-defined to the new type. If it's defined + * in different scope, a new symbol in current scope is created and the + * meaning is assigned to it. If it's already defined in the current scope, + * an error is reported via cf_error(). + * + * Result: Pointer to the newly defined symbol. If we are in the top-level + * scope, it's the same @sym as passed to the function. */ -void +struct symbol * cf_define_symbol(struct symbol *sym, int type, void *def) { if (sym->class) - cf_error("Symbol already defined"); + { + if (sym->scope == conf_this_scope) + cf_error("Symbol already defined"); + sym = cf_new_sym(sym->name, cf_hash(sym->name) & (SYM_HASH_SIZE-1)); + } sym->class = type; sym->def = def; + return sym; } static void diff --git a/conf/conf.h b/conf/conf.h index 24e3217..5d5e4bc 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -98,7 +98,7 @@ int cf_lex(void); void cf_lex_init(int is_cli); struct symbol *cf_find_symbol(byte *c); struct symbol *cf_default_name(char *template, int *counter); -void cf_define_symbol(struct symbol *symbol, int type, void *def); +struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def); void cf_push_scope(struct symbol *); void cf_pop_scope(void); struct symbol *cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos); |