]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Implement soft scopes
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Sun, 6 Mar 2022 15:37:30 +0000 (16:37 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 10 Mar 2022 01:02:32 +0000 (02:02 +0100)
Soft scopes are anonymous scopes that most likely do not contain any
symbol, so allocating regular scope is postponed when it is really
needed.

conf/cf-lex.l
conf/conf.h
sysdep/unix/main.c

index c9d2f5a5acd5241bce5e0f932ebb1fc644460ea7..d6f46223c984bc1ca79047e1fa94e10d346f0bb8 100644 (file)
@@ -574,6 +574,8 @@ check_eof(void)
   return 0;
 }
 
+static inline void cf_swap_soft_scope(void);
+
 static struct symbol *
 cf_new_symbol(const byte *c)
 {
@@ -583,6 +585,8 @@ cf_new_symbol(const byte *c)
   if (l > SYM_MAX_LEN)
     cf_error("Symbol too long");
 
+  cf_swap_soft_scope();
+
   s = cfg_allocz(sizeof(struct symbol) + l + 1);
   *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, };
   strcpy(s->name, c);
@@ -654,10 +658,10 @@ cf_localize_symbol(struct symbol *sym)
   /* If the symbol type is void, it has been recently allocated just in this scope. */
   if (!sym->class)
     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 (cf_symbol_is_local(sym))
+    cf_error("Symbol '%s' already defined", sym->name);
 
   /* Not allocated here yet, doing it now. */
   return cf_new_symbol(sym->name);
@@ -787,12 +791,60 @@ cf_push_scope(struct symbol *sym)
 void
 cf_pop_scope(void)
 {
+  ASSERT(!conf_this_scope->soft_scopes);
+
   conf_this_scope->active = 0;
   conf_this_scope = conf_this_scope->next;
 
   ASSERT(conf_this_scope);
 }
 
+/**
+ * cf_push_soft_scope - enter new soft scope
+ *
+ * If we want to enter a new anonymous scope that most likely will not contain
+ * any symbols, we can use cf_push_soft_scope() insteas of cf_push_scope().
+ * Such scope will be converted to a regular scope on first use.
+ */
+void
+cf_push_soft_scope(void)
+{
+  if (conf_this_scope->soft_scopes < 0xfe)
+    conf_this_scope->soft_scopes++;
+  else
+    cf_push_scope(NULL);
+}
+
+/**
+ * cf_pop_soft_scope - leave a soft scope
+ *
+ * Leave a soft scope entered by cf_push_soft_scope().
+ */
+void
+cf_pop_soft_scope(void)
+{
+  if (conf_this_scope->soft_scopes)
+    conf_this_scope->soft_scopes--;
+  else
+    cf_pop_scope();
+}
+
+/**
+ * cf_swap_soft_scope - convert soft scope to regular scope
+ *
+ * Soft scopes cannot hold symbols, so they must be converted to regular scopes
+ * on first use. It is done automatically by cf_new_symbol().
+ */
+static inline void
+cf_swap_soft_scope(void)
+{
+  if (conf_this_scope->soft_scopes)
+  {
+    conf_this_scope->soft_scopes--;
+    cf_push_scope(NULL);
+  }
+}
+
 /**
  * cf_symbol_class_name - get name of a symbol class
  * @sym: symbol
index 3bc37959ff54c5f52d4de6599afc0ac5cc7f95de..be46f172d8b378975ea547bcf0b06e58fbe7b460 100644 (file)
@@ -133,7 +133,8 @@ struct sym_scope {
   struct sym_scope *next;              /* Next on scope stack */
   struct symbol *name;                 /* Name of this scope */
   uint slots;                          /* Variable slots */
-  int active;                          /* Currently entered */
+  byte active;                         /* Currently entered */
+  byte soft_scopes;                    /* Number of soft scopes above */
 };
 
 struct bytestring {
@@ -190,6 +191,9 @@ 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);
 
+static inline int cf_symbol_is_local(struct symbol *sym)
+{ return (sym->scope == conf_this_scope) && !conf_this_scope->soft_scopes; }
+
 /**
  * cf_define_symbol - define meaning of a symbol
  * @sym: symbol to be defined
@@ -213,6 +217,9 @@ struct symbol *cf_localize_symbol(struct symbol *sym);
 
 void cf_push_scope(struct symbol *);
 void cf_pop_scope(void);
+void cf_push_soft_scope(void);
+void cf_pop_soft_scope(void);
+
 char *cf_symbol_class_name(struct symbol *sym);
 
 /* Parser */
index 392aff9d8755208f58a709371ecc825d4ae057f6..f87d0c4399ea08f02945b386f3bf7872a1beb286 100644 (file)
@@ -116,7 +116,7 @@ add_num_const(char *name, int val, const char *file, const uint line)
   struct f_val *v = cfg_alloc(sizeof(struct f_val));
   *v = (struct f_val) { .type = T_INT, .val.i = val };
   struct symbol *sym = cf_get_symbol(name);
-  if (sym->class && (sym->scope == conf_this_scope))
+  if (sym->class && cf_symbol_is_local(sym))
     cf_error("Error reading value for %s from %s:%d: already defined", name, file, line);
 
   cf_define_symbol(sym, SYM_CONSTANT | T_INT, val, v);