Filter: Implement soft scopes
Soft scopes are anonymous scopes that most likely do not contain any symbol, so allocating regular scope is postponed when it is really needed.
This commit is contained in:
parent
26bc4f9904
commit
946cedfcfe
3 changed files with 64 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue