#include "config.h" #include "types.h" #include "error.h" #include "lexer.h" #include "ops.h" #include "reg.h" #include "mem.h" #include "printf.h" #include "var.h" #include "printf.h" #include "str.h" #include "log.h" extern int verbose; #if HASH_VAR>0 /* First character of variable name to heap address mapping */ static address_t hashvar[26]; #endif /* Dual use: Allocates variable on heap or resolves address if exists already (and type and length is conforming) +----------+ size -1 | data+n | | .. | | data | <- addr | length | | name[] | <- top ... +----------+ 0 Scalar numbers occupy data field of var structure. Number arrays extend data field by (n-1) fields. Strings use data field + (n-4) following bytes. Events are stored here just to get a string name space. Payload is name field (addr)! Procs and funcs are stored here with data field containing the code address. Returns 0 if var is not found or wrong type or cannot be allocated. */ address_t Allocate(mem_t *M,reg_t *R, char *name, var_type type, index_t length, var_t **var) { index_t top; var_t *v=NULL; address_t addr=0; #if DEBUG > 0 log(LOGDEBUG1,"Allocate[%c:%d]? %s M[%d]\n",type,length,name,M->top); #endif #if HASH_VAR>0 // check hash/lut candidate by first character look-up if (hashvar[name[0]-'A']!=0) { top=hashvar[name[0]-'A']; v=(var_t*)(&M->data[top]); if (string_cmp(name,v->name,0)) goto varfound; } #endif top=M->top; while (top<(M->size-1)) { v=(var_t*)(&M->data[top]); if (string_cmp(name,v->name,0)) break; switch (v->type) { case MEVENT: case MVAR: case MCONST: top+=(var_s+(v->length-1)*number_s); break; case MSTRING: top+=(var_s+v->length-1); break; // these use data as address field and case MFUNC: // data: [address,args] top+=number_s; case MPROC: // data: [address] top+=var_s; break; #if HAS_FUNC>0 case MVARLOC: top+=(var_s+(v->length-1)*number_s); #endif break; } v=NULL; } varfound: if (v) { // check type consistency C V F P E and length switch (type) { case MVAR: case MCONST: #if HAS_FUNC>0 case MVARLOC: // frame pointer offset is stored in data field #endif if (v->type!=MVAR && v->type!=MVARLOC) { /*R->error=EVAR;*/ return 0; } if (length > 1 && v->length !=length) { /*R->error=EVAR;*/ return 0; } addr=(address_t)((char *)&v->data-(char*)M->data); if (var) *var=v; #if HASH_VAR>0 hashvar[name[0]-'A']=top; #endif // (stack) data addr pointer of local variables are stored in data field return addr; break; case MEVENT: case MSTRING: case MFUNC: // code address is stored in data field followed by nargs case MPROC: // code address is stored in data field if (length==1 && v->type!=type) { /*R->error=EVAR;*/ return 0; } else if (length>1 && (v->type!=type || (type==MSTRING?v->length:-v->length)!=length)) { /*R->error=EVAR;*/ return 0; } case MANY: // lookup only, no check if (v->type!=MEVENT) addr=(address_t)((char *)&v->data-(char*)M->data); else addr=(address_t)(&v->name[0]-(char*)M->data); if (var) *var=v; #if HASH_VAR>0 hashvar[name[0]-'A']=top; #endif return addr; break; } } else { if (type==MANY) return 0; // only lookup if (type==MEVENT) length=1; // pseudo string variable returning the name field as data address! else if (type==MSTRING && length==0) length=DEFSTRINGLEN+1; top=M->top-var_s-(length-1)*(type==MSTRING?1:number_s); top=top+(top%MEMALIGN); v=(var_t*)(&M->data[top]); string_copy(v->name,name,0); v->length=length; v->type=type; M->top=top; #if HASH_VAR>0 hashvar[name[0]-'A']=top; #endif } // new allocation if (type!=MEVENT) { addr=(address_t)((char *)&v->data-(char*)M->data); memset(&M->data[addr],0,length*(type==MSTRING?1:number_s)); } else addr=(address_t)(&v->name[0]-(char*)M->data); #if DEBUG > 0 log(LOGDEBUG1,"Allocate[%c:%d]: %s top=%d addr(->)=%d (var_s=%d)\n",type,length,name,M->top,addr,var_s); #endif #if HAS_LOCK > 0 LOCKDATA(v)=0; #endif if (var) *var=v; return addr; } void HeapInit() { #if HASH_VAR>0 memset(hashvar,0,sizeof(hashvar)); #endif }