return 0;
}
+static inline void cf_swap_soft_scope(void);
+
static struct symbol *
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);
/* 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);
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
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 {
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
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 */
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);