[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