[RFC PATCH 04/20] add support for defining typed symbols
Asbjørn Sloth Tønnesen
ast at 2e8.dk
Mon Dec 30 17:56:30 CET 2019
---
conf/cf-lex.l | 74 +++++++++++++++++++++++++++++++++++++++++--------
conf/conf.h | 37 ++++++++++++++++++++-----
conf/confbase.Y | 1 -
3 files changed, 93 insertions(+), 19 deletions(-)
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 1d6cae2c..9b7df0b2 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -73,10 +73,10 @@ 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->active
+#define SYM_KEY(n) n->name, n->scope->active, n->net_type
#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)
+#define SYM_EQ(a,s1,t1,b,s2,t2) !strcmp(a,b) && s1 == s2 && t1 == t2
+#define SYM_FN(k,s,t) cf_hash(k)
#define SYM_ORDER 6 /* Initial */
#define SYM_REHASH sym_rehash
@@ -544,7 +544,7 @@ check_eof(void)
}
static struct symbol *
-cf_new_symbol(const byte *c)
+cf_new_symbol(const byte *c, const u8 net_type)
{
struct symbol *s;
@@ -553,7 +553,11 @@ cf_new_symbol(const byte *c)
cf_error("Symbol too long");
s = cfg_allocz(sizeof(struct symbol) + l + 1);
- *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, };
+ *s = (struct symbol) {
+ .scope = conf_this_scope,
+ .class = SYM_VOID,
+ .net_type = net_type
+ };
strcpy(s->name, c);
if (!new_config->sym_hash.data)
@@ -566,6 +570,21 @@ cf_new_symbol(const byte *c)
return s;
}
+struct symbol *
+cf_find_typed_symbol(const struct config *cfg, const byte *c, const u8 net_type)
+{
+ struct symbol *s, *typed;
+ s = HASH_FIND(cfg->sym_hash, SYM, c, 1, NET_ANY);
+ if (!s) return NULL;
+ if (net_type == NET_ANY) return s;
+ if (!(s->flags & SYM_FLAG_IS_TYPED)) return NULL;
+
+ typed = HASH_FIND(cfg->sym_hash, SYM, c, 1, net_type);
+ if (!typed) return NULL;
+ cf_assert(s->scope == typed->scope, "bug: wrong scope");
+ return typed;
+}
+
/**
* cf_find_symbol - find a symbol by name
* @cfg: specificed config
@@ -583,13 +602,13 @@ cf_find_symbol(const struct config *cfg, const byte *c)
struct symbol *s;
if (cfg->sym_hash.data &&
- (s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
+ (s = HASH_FIND(cfg->sym_hash, SYM, c, 1, NET_ANY)))
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, 1)))
+ (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1, NET_ANY)))
return s;
return NULL;
@@ -607,7 +626,7 @@ cf_find_symbol(const struct config *cfg, const byte *c)
struct symbol *
cf_get_symbol(const byte *c)
{
- return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
+ return cf_find_symbol(new_config, c) ?: cf_new_symbol(c, NET_ANY);
}
/**
@@ -625,13 +644,46 @@ cf_localize_symbol(struct symbol *sym)
return sym;
/* If the scope is the current, it is already defined in this scope. */
- if (sym->scope == conf_this_scope)
- cf_error("Symbol already defined");
+ if (sym->scope == conf_this_scope) {
+ if (sym->flags & SYM_FLAGS_TYPED)
+ return sym;
+ else
+ cf_error("Symbol already defined");
+ }
/* Not allocated here yet, doing it now. */
- return cf_new_symbol(sym->name);
+ return cf_new_symbol(sym->name, NET_ANY);
}
+struct symbol *
+cf_type_symbol(struct symbol *sym, const int class, const u8 net_type)
+{
+ if (net_type == NET_ANY) {
+ if (sym->flags & SYM_FLAG_IS_TYPED)
+ cf_error("generic definitions not allowed for typed symbol");
+ else
+ return sym;
+ }
+
+ cf_assert(class & SYM_TYPEABLE, "Symbol not typeable");
+
+ if (sym->flags & SYM_FLAG_IS_TYPED && sym->class != class)
+ cf_error("Mixed symbol classes");
+
+ if (HASH_FIND(new_config->sym_hash, SYM, sym->name, 1, net_type))
+ cf_error("Symbol already defined for this channel type");
+
+ struct symbol *typed = cf_new_symbol(sym->name, net_type);
+
+ sym->class = class;
+ sym->flags |= SYM_FLAG_IS_TYPED;
+
+ cf_assert(typed->scope == new_config->root_scope, "wrong scope for typed symbol");
+
+ return typed;
+}
+
+
struct symbol *
cf_default_name(char *template, int *counter)
{
diff --git a/conf/conf.h b/conf/conf.h
index 39015e62..0104d070 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -15,6 +15,8 @@
#include "lib/resource.h"
#include "lib/timer.h"
+#define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0)
+
/* Configuration structure */
struct config {
@@ -112,6 +114,7 @@ struct symbol {
struct symbol *next;
struct sym_scope *scope;
int class; /* SYM_* */
+ u8 net_type; /* Routing table network type (NET_*), 0 for undefined */
uint flags; /* SYM_FLAG_* */
union {
@@ -184,31 +187,51 @@ void cf_lex_init(int is_cli, struct config *c);
void cf_lex_unwind(void);
struct symbol *cf_find_symbol(const struct config *cfg, const byte *c);
+struct symbol *cf_find_typed_symbol(const struct config *cfg, const byte *c, const u8 net_type);
struct symbol *cf_get_symbol(const byte *c);
struct symbol *cf_default_name(char *template, int *counter);
struct symbol *cf_localize_symbol(struct symbol *sym);
+struct symbol *cf_type_symbol(struct symbol *sym, const int class, const u8 net_type);
/**
- * cf_define_symbol - define meaning of a symbol
+ * cf_define_typed_symbol - define meaning of a symbol
* @sym: symbol to be defined
* @type: symbol class to assign
* @def: class dependent data
+ * @net_type: NET_* network type
*
* 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().
+ * an error is reported via cf_error(). If net_type is not %NET_ANY, a the
+ * typed version of the symbol will be returned.
+ *
+ * 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.
+ */
+#define cf_define_typed_symbol(sym_, type_, var_, def_, net_type_) ({ \
+ struct symbol *main_sym = cf_localize_symbol(sym_); \
+ struct symbol *typed = cf_type_symbol(main_sym, type_, net_type_); \
+ typed->class = type_; \
+ typed->var_ = def_; \
+ typed; })
+
+/**
+ * cf_define_symbol - define meaning of a symbol
+ * @sym: symbol to be defined
+ * @type: symbol class to assign
+ * @def: class dependent data
+ *
+ * This is a simple wrapper around %cf_define_typed_symbol, with
+ * net_type always passed as %NET_ANY.
*
* 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.
*/
-#define cf_define_symbol(sym_, type_, var_, def_) ({ \
- struct symbol *sym = cf_localize_symbol(sym_); \
- sym->class = type_; \
- sym->var_ = def_; \
- sym; })
+#define cf_define_symbol(sym_, type_, var_, def_) \
+ cf_define_typed_symbol(sym_, type_, var_, def_, NET_ANY)
void cf_push_scope(struct symbol *);
void cf_pop_scope(void);
diff --git a/conf/confbase.Y b/conf/confbase.Y
index 75158927..eda5b9c1 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -33,7 +33,6 @@ check_u16(uint val)
cf_error("Value %u out of range (0-65535)", val);
}
-#define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0)
static inline void cf_assert_symbol(const struct symbol *sym, uint class) {
switch (class) {
case SYM_PROTO: cf_assert(sym->class == SYM_PROTO, "Protocol name required"); break;
--
2.24.0
More information about the Bird-users
mailing list