#include "evalint.h" #include "variables.h" #include /* Is the adr field in a variable valid ? */ #define CLEAN(v) ((v)->adr && (v)->key == cache_time) long cache_time; /* This is incremented every time a variable is freed or created */ /* Variables are refered to by name, but this involves searching through a list at each reference, hence caching the address to speed things up. But these addresses may become invalid every time a varible is created/ deleted, hence this counter incremented at every such instance. Of course, after ~2 billion creations/deletions, there is a faint possibility of error, but I think I can live with it :-) */ context *current; void set_context(new) context *new; { current = new; cache_time++; } /* General variable creation routine */ vbl *_create_var(name) char *name; { register vbl *var; if (var = ALLOC(vbl)) { var->var_Node.ln_Name = ALLOCMEM(strlen(name) + 1); if (var->var_Node.ln_Name) { strcpy(var->var_Node.ln_Name, name); var->val = NULL; var->flags = NULL; AddHead(current, &var->var_Node); cache_time++; /* Invalidate addresses */ } else { FREE(vbl, var); var = NULL; } } return(var); } int create_var(v) variable *v; { vbl *new = _create_var(v->name); v->adr = new; v->key = cache_time; return(0 != new); } int create_var_name(name) char *name; { return(0 != _create_var(name)); } void free_var(v) variable *v; { register vbl *var; /* How to find the address of a varible : */ if (!CLEAN(v)) var = find_var(v->name); else var = v->adr; if (var) { Remove(&var->var_Node); FREEMEM(strlen(var->var_Node.ln_Name) + 1, var->var_Node.ln_Name); FREE(vbl, var); cache_time++; } } void free_var_name(name) char *name; { register vbl *var; if (var = find_var(name)) { Remove(&var->var_Node); FREEMEM(strlen(var->var_Node.ln_Name) + 1, var->var_Node.ln_Name); FREE(vbl, var); cache_time++; } } /* Return value of var */ value get_var(v) register variable *v; { if (CLEAN(v)) return(v->adr->val); else { v->adr = find_var(v->name); v->key = cache_time; if (v->adr) return(v->adr->val); else return(NULL); /* No such var */ } } value get_var_name(name) char *name; { vbl *v = find_var(name); if (v) return(v->val); else return(NULL); } /* set_var attempts to create the variable if it doesn't exist */ int set_var(v, val) register variable *v; value val; { if (!CLEAN(v)) { v->adr = find_var(v->name); v->key = cache_time; if (!v->adr) if (!(v->adr = _create_var(v->name))) return(FALSE); } v->adr->val = val; return(TRUE); } int set_var_name(name, val) char *name; value val; { register vbl *v = find_var(name); if (!v) if (!(v = _create_var(name))) return(FALSE); v->val = val; } void free_var_list(list) var_list *list; { register struct Node *scan, *node; scan = list->lh_Head; while (scan->ln_Succ) { node = scan; scan = scan->ln_Succ; Remove(node); FREEMEM(strlen(node->ln_Name) + 1, node->ln_Name); FREE(struct Node, node); } } /* Scan an expression to find all the variables it uses */ /* It can be called multiple times to find all the variables in multiple expressions */ var_list *make_var_list(expr, list) register value expr; var_list *list; { struct Node *node; char *str; switch (expr->type) { case var: if (!FindName(list, expr->vr.name)) /* Not already in list */ { int l = strlen(expr->vr.name) + 1; if ((node = ALLOC(struct Node)) && (str = ALLOCMEM(l))) { node->ln_Name = strcpy(str, expr->vr.name); AddTail(list, node); } else { if (node) FREE(struct Node, node); if (str) FREEMEM(l, str); free_vars(list); return(NULL); } } return(list); case op: if (make_var_list(expr->opr.arg1, list)) return(make_var_list(expr->opr.arg2, list)); else return(NULL); case fonc: return(make_var_list(expr->fn.arg, list)); case cste: return(list); } } /* Create all the vars in a list, if a variable already exists, its value is occulted by the new variable (till this one is freed) */ int create_vars(list) var_list *list; { register struct Node *scan; for (scan = list->lh_Head; scan->ln_Succ; scan = scan->ln_Succ) if (!_create_var(scan->ln_Name)) /* free vars */ { while (scan = scan->ln_Pred, scan->ln_Pred) free_var_name(scan->ln_Name); return(FALSE); } return(TRUE); } void free_vars(list) var_list *list; { register struct Node *scan; for (scan = list->lh_Head; scan->ln_Succ; scan = scan->ln_Succ) free_var_name(scan->ln_Name); }