mirror of
https://gitlab.labs.nic.cz/labs/bird.git
synced 2024-05-11 16:54:54 +00:00
Conf: Symbol hashes for all scopes
This is a backport cherry-pick of commits 165156beeb2926472bbceca3c103aacc3f81a8cc cce974e8ea992d0e6d2f649eca7880b436d91d71 from the v3.0 branch as we need symbol hashes directly inside their scopes for more general usage than before.
This commit is contained in:
committed by
Ondrej Zajicek
parent
a5a6de581b
commit
8e177cf35b
@ -73,22 +73,22 @@ static uint cf_hash(const byte *c);
|
||||
#define KW_FN(k) cf_hash(k)
|
||||
#define KW_ORDER 8 /* Fixed */
|
||||
|
||||
#define SYM_KEY(n) n->name, n->scope
|
||||
#define SYM_KEY(n) n->name
|
||||
#define SYM_NEXT(n) n->next
|
||||
#define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2
|
||||
#define SYM_FN(k,s) cf_hash(k) ^ ptr_hash(s)
|
||||
#define SYM_ORDER 6 /* Initial */
|
||||
#define SYM_EQ(a,b) !strcmp(a,b)
|
||||
#define SYM_FN(k) cf_hash(k)
|
||||
#define SYM_ORDER 4 /* Initial */
|
||||
|
||||
#define SYM_REHASH sym_rehash
|
||||
#define SYM_PARAMS /8, *1, 2, 2, 6, 20
|
||||
#define SYM_PARAMS /8, *1, 2, 2, 4, 20
|
||||
|
||||
|
||||
HASH_DEFINE_REHASH_FN(SYM, struct symbol)
|
||||
|
||||
HASH(struct keyword) kw_hash;
|
||||
|
||||
|
||||
struct sym_scope *conf_this_scope;
|
||||
struct sym_scope *global_root_scope;
|
||||
|
||||
linpool *cfg_mem;
|
||||
|
||||
@ -580,12 +580,13 @@ cf_new_symbol(const byte *c)
|
||||
*s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, };
|
||||
strcpy(s->name, c);
|
||||
|
||||
if (!new_config->sym_hash.data)
|
||||
HASH_INIT(new_config->sym_hash, new_config->pool, SYM_ORDER);
|
||||
if (!conf_this_scope->hash.data)
|
||||
HASH_INIT(conf_this_scope->hash, new_config->pool, SYM_ORDER);
|
||||
|
||||
HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s);
|
||||
HASH_INSERT2(conf_this_scope->hash, SYM, new_config->pool, s);
|
||||
|
||||
add_tail(&(new_config->symbols), &(s->n));
|
||||
if (conf_this_scope == new_config->root_scope)
|
||||
add_tail(&(new_config->symbols), &(s->n));
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -595,32 +596,27 @@ cf_symbol_from_keyword(const struct keyword *kw)
|
||||
{ return cf_new_symbol(kw->name); }
|
||||
|
||||
/**
|
||||
* cf_find_local_symbol - find a symbol by name
|
||||
* @cfg: specificed config
|
||||
* @scope: specified symbol scope
|
||||
* cf_find_symbol_scope - find a symbol by name
|
||||
* @scope: config scope
|
||||
* @c: symbol name
|
||||
*
|
||||
* This functions searches the symbol table in the config @cfg for a symbol of
|
||||
* given name. First it examines the scope @scope, then the parent scope
|
||||
* This functions searches the symbol table in the scope @scope for a symbol of
|
||||
* given name. First it examines the current scope, then the underlying one
|
||||
* and so on until it either finds the symbol and returns a pointer to its
|
||||
* &symbol structure or reaches the end of the scope chain and returns %NULL to
|
||||
* signify no match.
|
||||
*/
|
||||
struct symbol *
|
||||
cf_find_local_symbol(const struct config *cfg, const struct sym_scope *scope, const byte *c)
|
||||
cf_find_symbol_scope(const struct sym_scope *scope, const byte *c)
|
||||
{
|
||||
struct symbol *s;
|
||||
|
||||
if (cfg->sym_hash.data)
|
||||
for (; scope; scope = scope->next)
|
||||
if (s = HASH_FIND(cfg->sym_hash, SYM, c, scope))
|
||||
return s;
|
||||
|
||||
/* In CLI command parsing, fallback points to the current config, otherwise it is NULL. */
|
||||
if (cfg->fallback &&
|
||||
cfg->fallback->sym_hash.data &&
|
||||
(s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, cfg->fallback->root_scope)))
|
||||
return s;
|
||||
/* Find the symbol here or anywhere below */
|
||||
while (scope)
|
||||
if (scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c)))
|
||||
return s;
|
||||
else
|
||||
scope = scope->next;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -637,7 +633,7 @@ cf_find_local_symbol(const struct config *cfg, const struct sym_scope *scope, co
|
||||
struct symbol *
|
||||
cf_get_symbol(const byte *c)
|
||||
{
|
||||
return cf_find_local_symbol(new_config, conf_this_scope, c) ?: cf_new_symbol(c);
|
||||
return cf_find_symbol_scope(conf_this_scope, c) ?: cf_new_symbol(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -685,23 +681,15 @@ static enum yytokentype
|
||||
cf_lex_symbol(const char *data)
|
||||
{
|
||||
/* Have we defined such a symbol? */
|
||||
struct symbol *sym = cf_find_local_symbol(new_config, conf_this_scope, data);
|
||||
struct symbol *sym = cf_get_symbol(data);
|
||||
cf_lval.s = sym;
|
||||
|
||||
if (sym && (sym->class != SYM_VOID))
|
||||
{
|
||||
cf_lval.s = sym;
|
||||
return CF_SYM_KNOWN;
|
||||
}
|
||||
|
||||
/* Is it a keyword? */
|
||||
/* Is it a keyword? Prefer the keyword. */
|
||||
struct keyword *k = HASH_FIND(kw_hash, KW, data);
|
||||
if (k)
|
||||
{
|
||||
if (k->value > 0)
|
||||
{
|
||||
cf_lval.kw = k;
|
||||
return k->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
cf_lval.i = -k->value;
|
||||
@ -709,19 +697,23 @@ cf_lex_symbol(const char *data)
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, undefined symbol */
|
||||
cf_lval.s = cf_new_symbol(data);
|
||||
return CF_SYM_UNDEFINED;
|
||||
/* OK, only a symbol. */
|
||||
if (sym->class == SYM_VOID)
|
||||
return CF_SYM_UNDEFINED;
|
||||
else
|
||||
return CF_SYM_KNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
cf_lex_init_kh(void)
|
||||
{
|
||||
HASH_INIT(kw_hash, config_pool, KW_ORDER);
|
||||
HASH_INIT(kw_hash, &root_pool, KW_ORDER);
|
||||
|
||||
struct keyword *k;
|
||||
for (k=keyword_list; k->name; k++)
|
||||
HASH_INSERT(kw_hash, KW, k);
|
||||
|
||||
global_root_scope = mb_allocz(&root_pool, sizeof(*global_root_scope));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -757,6 +749,11 @@ cf_lex_init(int is_cli, struct config *c)
|
||||
c->root_scope = cfg_allocz(sizeof(struct sym_scope));
|
||||
conf_this_scope = c->root_scope;
|
||||
conf_this_scope->active = 1;
|
||||
|
||||
if (is_cli)
|
||||
conf_this_scope->next = config->root_scope;
|
||||
else
|
||||
conf_this_scope->next = global_root_scope;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,7 +170,6 @@ int
|
||||
cli_parse(struct config *c)
|
||||
{
|
||||
int done = 0;
|
||||
c->fallback = config;
|
||||
new_config = c;
|
||||
cfg_mem = c->mem;
|
||||
if (setjmp(conf_jmpbuf))
|
||||
@ -181,7 +180,6 @@ cli_parse(struct config *c)
|
||||
done = 1;
|
||||
|
||||
cleanup:
|
||||
c->fallback = NULL;
|
||||
new_config = NULL;
|
||||
cfg_mem = NULL;
|
||||
return done;
|
||||
@ -551,7 +549,6 @@ order_shutdown(int gr)
|
||||
init_list(&c->tables);
|
||||
init_list(&c->symbols);
|
||||
memset(c->def_tables, 0, sizeof(c->def_tables));
|
||||
HASH_INIT(c->sym_hash, c->pool, 4);
|
||||
c->shutdown = 1;
|
||||
c->gr_down = gr;
|
||||
|
||||
|
21
conf/conf.h
21
conf/conf.h
@ -16,7 +16,6 @@
|
||||
#include "lib/timer.h"
|
||||
|
||||
/* Configuration structure */
|
||||
|
||||
struct config {
|
||||
pool *pool; /* Pool the configuration is stored in */
|
||||
linpool *mem; /* Linear pool containing configuration data */
|
||||
@ -53,8 +52,7 @@ struct config {
|
||||
char *err_file_name; /* File name containing error */
|
||||
char *file_name; /* Name of main configuration file */
|
||||
int file_fd; /* File descriptor of main configuration file */
|
||||
HASH(struct symbol) sym_hash; /* Lexer: symbol hash table */
|
||||
struct config *fallback; /* Link to regular config for CLI parsing */
|
||||
|
||||
struct sym_scope *root_scope; /* Scope for root symbols */
|
||||
int obstacle_count; /* Number of items blocking freeing of this config */
|
||||
int shutdown; /* This is a pseudo-config for daemon shutdown */
|
||||
@ -133,12 +131,17 @@ struct symbol {
|
||||
struct sym_scope {
|
||||
struct sym_scope *next; /* Next on scope stack */
|
||||
struct symbol *name; /* Name of this scope */
|
||||
|
||||
HASH(struct symbol) hash; /* Local symbol hash */
|
||||
|
||||
uint slots; /* Variable slots */
|
||||
byte active; /* Currently entered */
|
||||
byte block; /* No independent stack frame */
|
||||
byte soft_scopes; /* Number of soft scopes above */
|
||||
};
|
||||
|
||||
extern struct sym_scope *global_root_scope;
|
||||
|
||||
struct bytestring {
|
||||
size_t length;
|
||||
byte data[];
|
||||
@ -187,12 +190,14 @@ int cf_lex(void);
|
||||
void cf_lex_init(int is_cli, struct config *c);
|
||||
void cf_lex_unwind(void);
|
||||
|
||||
struct symbol *cf_find_local_symbol(const struct config *cfg, const struct sym_scope *scope, const byte *c);
|
||||
static inline struct symbol *cf_find_symbol(const struct config *cfg, const byte *c)
|
||||
{ return cf_find_local_symbol(cfg, cfg->root_scope, c); }
|
||||
struct symbol *cf_find_symbol_scope(const struct sym_scope *scope, const byte *c);
|
||||
static inline struct symbol *cf_find_symbol_cfg(const struct config *cfg, const byte *c)
|
||||
{ return cf_find_symbol_scope(cfg->root_scope, c); }
|
||||
|
||||
struct keyword;
|
||||
struct symbol *cf_symbol_from_keyword(const struct keyword *kw);
|
||||
#define cf_find_symbol(where, what) _Generic(*(where), \
|
||||
struct config: cf_find_symbol_cfg, \
|
||||
struct sym_scope: cf_find_symbol_scope \
|
||||
)((where), (what))
|
||||
|
||||
struct symbol *cf_get_symbol(const byte *c);
|
||||
struct symbol *cf_default_name(char *template, int *counter);
|
||||
|
@ -118,7 +118,7 @@ CF_DECLS
|
||||
|
||||
%type <t> text opttext
|
||||
%type <bs> bytestring
|
||||
%type <s> symbol
|
||||
%type <s> symbol symbol_known
|
||||
|
||||
%type <v> bytestring_text text_or_ipa
|
||||
%type <x> bytestring_expr
|
||||
@ -166,7 +166,7 @@ definition:
|
||||
expr:
|
||||
NUM
|
||||
| '(' term ')' { $$ = cf_eval_int($2); }
|
||||
| CF_SYM_KNOWN {
|
||||
| symbol_known {
|
||||
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
|
||||
$$ = SYM_VAL($1).i; }
|
||||
;
|
||||
@ -177,7 +177,8 @@ expr_us:
|
||||
| expr US { $$ = $1 US_; }
|
||||
;
|
||||
|
||||
symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | KEYWORD { $$ = cf_symbol_from_keyword($1); } ;
|
||||
symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | KEYWORD ;
|
||||
symbol_known: CF_SYM_KNOWN | KEYWORD ;
|
||||
|
||||
/* Switches */
|
||||
|
||||
|
@ -26,8 +26,7 @@ m4_define(CF_DEFINES, `m4_divert(-1)')
|
||||
m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1, NULL },
|
||||
m4_divert(-1)')
|
||||
m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_handle_kw($1)]])')
|
||||
m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks
|
||||
)DNL')
|
||||
m4_define(CF_KEYWORDS, `CF_iterate([[CF_keywd]], [[$@]])DNL')
|
||||
m4_define(CF_KEYWORDS_EXCLUSIVE, `CF_KEYWORDS($@)')
|
||||
|
||||
# CLI commands generate keywords as well
|
||||
|
@ -31,13 +31,13 @@ m4_define(CF_iterate, `m4_define([[CF_iter]], m4_defn([[$1]]))CF_itera($2)')
|
||||
|
||||
m4_define(CF_append, `m4_define([[$1]], m4_ifdef([[$1]], m4_defn([[$1]])[[$3]])[[$2]])')
|
||||
|
||||
# Keywords act as %token<kw>
|
||||
# Keywords act as %token<s>
|
||||
m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_append([[CF_kw_rule]],$1,[[ | ]])m4_define([[CF_toks]],CF_toks $1)]])')
|
||||
m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token<kw>[[]]CF_toks
|
||||
m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token<s>[[]]CF_toks
|
||||
)DNL')
|
||||
|
||||
m4_define(CF_keywd2, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_define([[CF_toks]],CF_toks $1)]])')
|
||||
m4_define(CF_KEYWORDS_EXCLUSIVE, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd2]], [[$@]])m4_ifelse(CF_toks,,,%token<kw>[[]]CF_toks
|
||||
m4_define(CF_KEYWORDS_EXCLUSIVE, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd2]], [[$@]])m4_ifelse(CF_toks,,,%token<s>[[]]CF_toks
|
||||
)DNL')
|
||||
|
||||
# CLI commands
|
||||
@ -61,7 +61,7 @@ m4_undivert(1)DNL
|
||||
|
||||
m4_undivert(2)DNL
|
||||
|
||||
%type <kw> KEYWORD
|
||||
%type <s> KEYWORD
|
||||
|
||||
%%
|
||||
KEYWORD: CF_kw_rule;
|
||||
|
Reference in New Issue
Block a user