summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>2000-06-04 21:30:13 +0200
committerMartin Mares <mj@ucw.cz>2000-06-04 21:30:13 +0200
commit04dc62a0116941d2f1510216539ae8c11c5f1cb3 (patch)
treeead689c0378fa535ecb3ae7dbe9d86f98c043653
parentdab66519160042f1fb62a285e3a947233ce74e70 (diff)
downloadbird-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.l59
-rw-r--r--conf/conf.h2
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);