value_t * eppic_exevar(void *arg) { vnode_t *vn = arg; value_t *nv; var_t*curv; srcpos_t pos; eppic_curpos(&vn->n->pos, &pos); if(!(curv=eppic_getvarbyname(vn->name, 0, 0))) { eppic_error("Oops! Var ref1.[%s]", vn->name); } if(!curv->ini && !insizeof && !vlev) { eppic_error("Variable [%s] used before being initialized", curv->name); } nv=eppic_newval(); eppic_dupval(nv,curv->v); nv->set=1; nv->setval=curv->v; nv->setfct=eppic_setfct; eppic_curpos(&pos, 0); return nv; }
/* This function is called to validate variable declaration. No array decalration for variables (this can only be checked in eppic_stat_decl() and eppic_file_decl() usingthe idx field ofthe var struct. Same comment for nbits. Only in struct declarations. */ void eppic_validate_vars(var_t*svs) { var_t*v, *next; if(!svs) return; for(v=svs->next; v!=svs; v=next) { next=v->next; /* just remove extern variables */ if(eppic_isxtern(v->v->type.typattr)) { eppic_dequeue(v); eppic_freevar(v); } else { if(v->dv->idx) { eppic_freesvs(svs); eppic_error("Array instanciations not supported."); } if(v->dv->nbits) { eppic_freesvs(svs); eppic_error("Syntax error. Bit field unexpected."); } } } }
node_t* eppic_newstr() { int maxl=S_MAXSTRLEN; char *buf=eppic_alloc(maxl); int iline=eppic_line(0); int i, c; /* let the input function knwo we want averyting from the input stream. Comments and all... */ eppic_rawinput(1); for(i=0;i<maxl;i++) { c=eppic_input(); switch(c) { case '\\': /* escape sequence */ switch(c=eppic_input()) { case 'x': /* hexa value_t */ buf[i]=eppic_getnum(16); break; case '0': /* octal value_t */ buf[i]=eppic_getnum(8); break; default : if(isdigit(c)) { eppic_unput(c); buf[i]=eppic_getnum(10); } else { buf[i]=eppic_getseq(c); } break; } break; case '"': /* we're finished */ { buf[i]='\0'; eppic_rawinput(0); return eppic_allocstr(buf); } case (-1): eppic_error("Unterminated string at line %d", iline); break; default: buf[i]=c; break; } } eppic_error("String too long at %d", iline); return NULLNODE; }
/* Print a struct/union type or value */ static void eppic_print_ctype(type_t *t, value_t *v, int level, int indent, char *name, int ref, int justv) { stinfo_t *st=eppic_getstbyindex(t->idx, t->type); stmember_t *m; char buf[100]; if(!st) eppic_error("Oops eppic_print_ctype!"); if(!st->all) { eppic_fillst(st); if(!st->all) eppic_error("Reference to a incomplete type"); } eppic_indent(level, indent); if(!justv) { snprintf(buf, sizeof(buf)-1, "%s %s", eppic_ctypename(t->type), st->name?st->name:""); eppic_msg("%-*s ", SPACER, buf); /* is this is a pointer, bail out */ } if(ref) return; if(v && !justv) eppic_msg(" = "); eppic_msg("{\n"); for(m=st->stm; m; m=m->next) { value_t *vm=0; eppic_indent(level+1, 1); if(v) { vm=eppic_newval(); eppic_duptype(&vm->type, &m->type); eppic_exememlocal(v, m, vm); eppic_ptype2(&vm->type, vm, level+1, 0, m->m.name, 0, 0); } else eppic_ptype2(&m->type, vm, level+1, 0, m->m.name, 0, 0); eppic_msg(";\n"); if(vm) eppic_freeval(vm); } eppic_indent(level, 1); eppic_msg("}"); if(name) eppic_msg(" %s", name); }
void eppic_popjmp(int type) { if(!njmps) { eppic_error("Pop underflow!"); } njmps--; if(jmps[njmps].type != type) { eppic_error("Wrong pop! %d vs %d", jmps[njmps].type, type); } eppic_setsvlev(jmps[njmps].svlev); }
int eppic_addsvs(int type, var_t*sv) { int curlev=svlev; if(svlev==S_MAXDEEP) { eppic_error("Svars stack overflow"); } else { svs[svlev].type=type; svs[svlev].svs=sv; eppic_setsvlev(eppic_getsvlev()+1); /* perform automatic initializations */ eppic_inivars(sv, type==S_PARSE); /* if S_FILE then we are entering a function so start a newset of stack variables */ if(type == S_FILE ) { (void)eppic_addsvs(S_AUTO, (var_t*)eppic_newvlist()); } } return curlev; }
static void eppic_free_bl(blist *bl, void *ra) { bl->freer=ra; bl->prev->next=bl->next; bl->next->prev=bl->prev; #ifdef MEMDEBUG if(memdebug) { /* help out dbx/gdb when they're watching the allocated area by writing over it */ { int i, ni=bl->size/sizeof(void*); char *p=(char*)bl; unsigned long up; for(i=0;i<ni;i++) ((char **)p)[i]=ra; up=(unsigned long)p; if(*((int*)(up-4)) != MAGIC) eppic_error("Oops eppic_free"); up=up ^ (up & (PAGESIZE-1)); mprotect((void*)up, PAGESIZE, PROT_READ); } } else { free(bl); } #else free(bl); #endif }
eppic_vpop() { if(vlev) { eppic_setsvlev(sidx[--vlev]); } else eppic_error("Too many parse var pops!"); }
/* scan the current array for a specific index and return value_t XXX should use some hashing tables here for speed and scalability */ array_t* eppic_getarrval(array_t**app, value_t *idx) { array_t*ap, *apr; /* eppic_setarray(app); AAA comment out */ apr=*app; for(ap=apr->next; ap != apr; ap=ap->next) { if(ap->idx->type.type == idx->type.type) { int b=0; switch(idx->type.type) { case V_STRING: b=(!strcmp(ap->idx->v.data, idx->v.data)); break; case V_BASE: b=(unival(ap->idx)==unival(idx)); break; case V_REF: if(eppic_defbsize()==4) b=(ap->idx->v.ul==idx->v.ul); else b=(ap->idx->v.ull==idx->v.ull); break; default: eppic_error("Invalid index type %d", idx->type.type); } if(b) { return ap; } } } /* we have not found this index, create one */ ap=(array_t*)eppic_calloc(sizeof(array_t)); ap->idx=eppic_makebtype(0); eppic_dupval(ap->idx, idx); /* just give it a int value_t of 0 for now */ ap->val=eppic_makebtype(0); /* we must set the same refenrence number as the upper level array_t*/ ap->val->arr->ref=apr->ref; /* link it in */ ap->prev=apr->prev; ap->next=apr; apr->prev->next=ap; apr->prev=ap; ap->ref=0; return ap; }
/* mult is a special case since the parse always return a PTR token for the '*' signed. The PTR token value_t is the number of '* found. */ node_t* eppic_newmult(node_t*n1, node_t*n2, int n) { if(n>1) { eppic_error("Syntax error"); } return eppic_newop(MUL, 2, n1, n2); }
idx_t * eppic_addidx(idx_t *idx, node_t*n) { if(idx->nidx==MAXIDX) { eppic_error("Maximum number of dimension is %d", MAXIDX); } idx->idxs[idx->nidx++]=n; return idx; }
eppic_vpush() { if(vlev==S_MAXSDEEP) { eppic_error("Too many nested compound statements!"); } else { sidx[vlev]=svlev; vlev++; } }
ul eppic_bool(value_t *v) { switch(v->type.type) { case V_BASE: switch(v->type.size) { case 1: return !(!(v->v.uc)); case 2: return !(!(v->v.us)); case 4: return !(!(v->v.ul)); case 8: return !(!(v->v.ull)); default: eppic_error("Oops eppic_bool()[%d]", v->type.size); break; } case V_STRING : return !(!(*((char*)(v->v.data)))); case V_REF: return eppic_defbsize()==8?(!(!(v->v.ull))):(!(!(v->v.ul))); default : eppic_error("Invalid operand for boolean expression"); return 0; } }
/* This is where we implement the variable scoping. */ var_t* eppic_getvarbyname(char *name, int silent, int local) { var_t*vp; int i, aidx=0; ull apiv, mem; for(i=svlev-1; i>=0; i--) { if((vp=eppic_inlist(name, svs[i].svs))) { return vp; } if(svs[i].type==S_AUTO && !aidx) aidx=i; /* when we get to the function we're finished */ if(svs[i].type==S_FILE) break; } /* have'nt found any variable named like this one */ /* first check the globals */ if(!(vp=eppic_inglobs(name))) { int off=0; /* check the API for a corresponding symbol */ /* Jump over possible leading "IMG_" prefix */ if(!strncmp(name, "IMG_", 4)) off=4; if(!local) { vp=eppic_newvar(name); if(API_GETVAL(name+off, &apiv, eppic_legacy?0:vp->v)) { vp->ini=1; if(eppic_legacy) { eppic_defbtype(vp->v, apiv); vp->v->mem=apiv; } /* put this on the global list */ eppic_enqueue(apiglobs, vp); } else { eppic_freevar(vp); vp=0; } } else { if(silent) return 0; eppic_error("Unknown variable [%s]", name); } } return vp; }
idx_t * eppic_newidx(node_t*n) { idx_t *idx; if(!instruct) { eppic_error("Array supported only in struct/union declarations"); } idx=eppic_alloc(sizeof(idx_t)); idx->nidx=1; idx->idxs[0]=n; return idx; }
void eppic_addtolist(var_t*vl, var_t*v) { if(!v->name[0] || !eppic_inlist(v->name, vl)) { eppic_enqueue(vl, v); } else { /* if this is a prototype declaration then skip it */ if(v->dv && v->dv->fct) return; eppic_error("Duplicate declaration of variable %s", v->name); } }
void eppic_pushjmp(int type, void *venv, void *val) { jmp_buf *env=(jmp_buf *)venv; if(njmps<MAXJMPS) { jmps[njmps].type=type; jmps[njmps].val=(value_t**)val; jmps[njmps].env=env; jmps[njmps++].svlev=eppic_getsvlev(); } else { eppic_error("Jump Stack overflow"); } }
void eppic_valindex(value_t *var, value_t *idx, value_t *ret) { if(is_ctype(idx->type.type)) { eppic_error("Invalid indexing type"); } else { array_t*a; a=eppic_getarrval(&var->arr, idx); /* this is the first level of indexing through a variable */ eppic_dupval(ret, a->val); ret->set=1; ret->setval=a->val; } }
/* get the name of a function through a variable */ char * eppic_vartofunc(node_t*name) { char *vname=NODE_NAME(name); value_t *val; /* if the nore is a general expression, then vname is 0 */ if(!vname) { val=eppic_exenode(name); } else { var_t*v; v=eppic_getvarbyname(vname, 1, 1); if(!v) return vname; val=v->v; } switch(val->type.type) { case V_STRING: { char *p=eppic_alloc(val->type.size+1); /* return the value_t of that string variable */ strcpy(p, val->v.data); eppic_free(vname); return p; } default: /* return the name of the variable itself */ eppic_error("Invalid type for function pointer, expected 'string'."); return vname; } }
void eppic_do_deref(int n, value_t *v, value_t *ref) { ull madr, new_madr; if(n > ref->type.ref) { eppic_error("Too many levels of dereference"); }else { if(eppic_defbsize()==4) madr=(ull)ref->v.ul; else madr=ref->v.ull; /* copy the target type to the returned value_t's type_t*/ eppic_duptype(&v->type, &ref->type); /* do a number of deferences according to PTR value_t */ while(n--) { eppic_popref(&v->type, 1); if(!v->type.ref) { /* make sure the pointer is pointing into the vmcore */ if(is_ctype(v->type.type)) { v->v.data=eppic_alloc(v->type.size); eppic_getmem(madr, v->v.data, v->type.size); } else { /* get the data from the system image */ switch(TYPE_SIZE(&v->type)) { case 1: eppic_getmem(madr, &v->v.uc, 1); break; case 2: eppic_getmem(madr, &v->v.us, 2); break; case 4: eppic_getmem(madr, &v->v.ul, 4); break; case 8: eppic_getmem(madr, &v->v.ull, 8); break; } } } else { /* get the pointer at this address */ if(eppic_defbsize()==4) { eppic_getmem(madr, &v->v.ul, 4); new_madr=v->v.ul; } else { eppic_getmem(madr, &v->v.ull, 8); new_madr=v->v.ull; } } /* remember this address. For the '&' operator */ v->mem=madr; madr=new_madr; } } /* we can always assign to a reference */ v->set=1; v->setval=v; v->setfct=eppic_setderef; }
static value_t * eppic_exeop(oper *o) { value_t *v=0, *v1=0, *v2=0, *v3=0, *v4=0; int top; srcpos_t p; eppic_curpos(&o->pos, &p); /* if ME (op on myself) operator, translate to normal operator we will re-assign onto self when done */ top=getop(o->op); if(top == ASSIGN) { goto doop; } else if(top == IN) { /* the val in array[] test is valid for anything but struct/union */ v=eppic_makebtype((ull)eppic_lookuparray(P1,P2)); } else if(is_cond(top)) { /* the operands are eithr BASE (integer) or REF (pointer) */ /* all conditional operators accept a mixture of pointers and integer */ /* set the return as a basetype even if bool */ switch(top) { case CEXPR: { /* conditional expression expr ? : stmt : stmt */ if(eppic_bool(V1)) { v=eppic_cloneval(V2); } else { v=eppic_cloneval(V3); } } break; case BOR: { /* a || b */ v=eppic_makebtype((ull)(eppic_bool(V1) || eppic_bool(V2))); } break; case BAND: { /* a && b */ v=eppic_makebtype((ull)(eppic_bool(V1) && eppic_bool(V2))); } break; case NOT: { /* ! expr */ v=eppic_makebtype((ull)(! eppic_bool(V1))); } break; default: { v=eppic_docomp(top, V1, V2); } } } else if(anyop(V_STRING)) { if(top == ADD) { char *buf; if(V1->type.type != V_STRING || V2->type.type != V_STRING) { eppic_rerror(&P1->pos, "String concatenation needs two strings!"); } buf=eppic_alloc(strlen(S1)+strlen(S2)+1); strcpy(buf, S1); strcat(buf, S2); v=eppic_makestr(buf); eppic_free(buf); } else { eppic_rerror(&P1->pos, "Invalid string operator"); } } /* arithmetic operator */ else if(anyop(V_REF)) { int size; value_t *vt; /* make sure we have the base type second */ if(V1->type.type != V_REF) { vt=V1; v1=V2; v2=vt; } if(V1->type.type == V_BASE) { inval: eppic_error("Invalid operand on pointer operation"); } /* get the size of whas we reference */ size=V1->type.size; switch(top) { case ADD: { /* expr + expr */ /* adding two pointers ? */ if(V2->type.type == V_REF) goto inval; V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) + L2 * size); } break; case SUB: { /* expr - expr */ /* different results if mixed types. if both are pointers then result is a V_BASE */ if(V2->type.type == V_REF) v=eppic_makebtype(L1 - L2); else { V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) - L2 * size); } } break; case PREDECR: { /* pre is easy */ V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) - size); eppic_setval(v1, v); } break; case PREINCR: { V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) + size); eppic_setval(v1, v); } break; case POSTINCR: { V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) + size); eppic_setval(v1, v); eppic_transfer(v, v1, unival(v1)); } break; case POSTDECR: { V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) - size); eppic_setval(v1, v); eppic_transfer(v, v1, unival(v1)); } break; default: eppic_error("Invalid operation on pointer [%d]",top); } } else { /* both operands are V_BASE */ switch(top) { /* for mod and div, we check for divide by zero */ case MOD: case DIV: if(!L2) { eppic_rerror(&P1->pos, "Mod by zero"); } case ADD: case SUB: case MUL: case XOR: case OR: case AND: case SHL: case SHR: { eppic_baseop(top, V1, V2, v=eppic_newval()); } break; case UMINUS: { value_t *v0=eppic_newval(); eppic_defbtype(v0, (ull)0); /* keep original type of v1 */ v=eppic_newval(); eppic_duptype(&v0->type, &V1->type); eppic_duptype(&v->type, &V1->type); eppic_baseop(SUB, v0, V1, v); eppic_freeval(v0); /* must make result signed */ eppic_mkvsigned(v); } break; case FLIP: { value_t *v0=eppic_newval(); eppic_defbtype(v0, (ull)0xffffffffffffffffll); /* keep original type of v1 */ eppic_duptype(&v0->type, &V1->type); eppic_baseop(XOR, v0, V1, v=eppic_newval()); eppic_freeval(v0); } break; case PREDECR: { /* pre is easy */ V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) - 1); eppic_setval(v1, v); } break; case PREINCR: { V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) + 1); eppic_setval(v1, v); } break; case POSTINCR: { V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) + 1); eppic_setval(v1, v); eppic_transfer(v, v1, unival(v1)); } break; case POSTDECR: { V1; eppic_transfer(v=eppic_newval(), v1, unival(v1) - 1); eppic_setval(v1, v); eppic_transfer(v, v1, unival(v1)); } break; default: eppic_rerror(&P1->pos, "Oops ops ! [%d]", top); } } doop: /* need to assign the value_t back to P1 */ if(top != o->op || top==ASSIGN) { /* in the case the Lvalue_t is a variable , bypass execution and set ini */ if(P1->exe == eppic_exevar) { char *name=NODE_NAME(P1); var_t*va=eppic_getvarbyname(name, 0, 0); value_t *vp; eppic_free(name); if(top != o->op) vp=v; else vp=V2; eppic_chkandconvert(va->v, vp); eppic_freeval(v); v=eppic_cloneval(va->v); va->ini=1; } else { if(!(V1->set)) { eppic_rerror(&P1->pos, "Not Lvalue_t on assignment"); } else { /* if it's a Me-op then v is already set */ V1; if(top != o->op) { eppic_setval(v1, v); } else { eppic_setval(v1, V2); v=eppic_cloneval(V2); } } } /* the result of a assignment if not an Lvalue_t */ v->set=0; } eppic_freeval(v1); eppic_freeval(v2); eppic_freeval(v3); eppic_freeval(v4); eppic_setpos(&p); return v; }
static value_t* eppic_docomp(int op, value_t *v1, value_t *v2) { /* if one parameter is string then both must be */ if(v1->type.type == V_STRING || v2->type.type == V_STRING) { if(v1->type.type != V_STRING || v2->type.type != V_STRING) { eppic_error("Invalid condition arguments"); } else { switch(op) { case EQ: { /* expr == expr */ return eppic_makebtype(!strcmp(v1->v.data, v2->v.data)); } case GT: case GE: { /* expr > expr */ return eppic_makebtype(strcmp(v1->v.data, v2->v.data) > 0); } case LE: case LT: { /* expr <= expr */ return eppic_makebtype(strcmp(v1->v.data, v2->v.data) < 0); } case NE: { /* expr != expr */ return eppic_makebtype(strcmp(v1->v.data, v2->v.data)); } default: { eppic_error("Oops conditional unknown 1"); } } } } else { int idx1, idx2; value_t *v=eppic_newval(); /* make sure pointers are forced to proper basetype before calling eppic_baseop()*/ idx1=eppic_reftobase(v1); idx2=eppic_reftobase(v2); switch(op) { case EQ: case GT: case GE: case LE: case LT: case NE: eppic_baseop(op, v1, v2, v); break; default: { eppic_error("Oops conditional unknown 2"); } } v1->type.idx=idx1; v2->type.idx=idx2; return v; } return 0; }
/* this is the main variable declaration function. We support the global scope attribute that make the declared variable accessible to all function from all scripts. By default the scope of a variable either the statement block where it was declared (or first used): { int var; ... } Then it's scope is the block itself. Or the file, if it was declared outside of a function. Storage is by default 'automatic' and can be made permanent by using the 'static' keywork in the declaration. 'Volatile' and 'register' storage classes are supported but have no effect. */ var_t* eppic_vardecl(dvar_t*dv, type_t*t) { var_t*vlist=eppic_newvlist(); var_t*var; /* type *and* dv can have ref counts. First comes from typedef parsing second comes from the declaration itself */ dv->ref += t->ref; /* add one level of ref for arrays */ if(dv->idx) dv->ref++; /* reset ref level for tests below */ eppic_popref(t, t->ref); TAG(vlist); if(!t->type) { int sto=eppic_isstor(t->typattr); eppic_freetype(t); t=eppic_newbtype(0); t->typattr |= sto; } else if(t->type==V_BASE && !dv->ref) { eppic_chksign(t); eppic_chksize(t); } /* is this a new typedef declaration ? */ /* typedef is considered just like any other storage class */ if(eppic_istdef(t->typattr)) { eppic_tdef_decl(dv, t); return 0; } while(dv) { /* disalow var names that match against already defined vars */ if(dv->name[0]) { type_t *t=eppic_getctype(V_TYPEDEF, dv->name, 1); if(t) { eppic_freetype(t); eppic_warning("Variable '%s' already defined as typedef.\n"); } } /* some sanity checks here that apply to both var and struct declarations */ if(is_ctype(t->type) && !dv->ref) { if(dv->name[0]) { if(!instruct) { if(!eppic_isxtern(t->typattr)) { eppic_freesvs(vlist); eppic_error("struct/union instances not supported, please use pointers"); } } else if(eppic_ispartial(t)) { eppic_freesvs(vlist); eppic_error("Reference to incomplete type"); } } } if(dv->nbits) { if(t->type != V_BASE) { eppic_freesvs(vlist); eppic_error("Bit fields can only be of integer type"); } if(dv->idx) { eppic_freesvs(vlist); eppic_error("An array of bits ? Come on..."); } } var=eppic_newvar(dv->name); t->fct=dv->fct; eppic_duptype(&var->v->type, t); eppic_pushref(&var->v->type, dv->ref); var->dv=dv; TAG(var); if(t->type == V_STRING) { eppic_setstrval(var->v, ""); } eppic_setpos(&dv->pos); /* toff */ /* add to parsing list */ if(var->name[0]) { var_t *plist=eppic_newvlist(); eppic_enqueue(plist, var); eppic_addsvs(S_PARSE, eppic_dupvlist(plist)); } eppic_enqueue(vlist, var); next: dv=dv->next; } eppic_free(t); TAG(vlist); return vlist; }