📄 mal_instruction.mx
字号:
well-known coercion rules. Errors are reported and thenil value is set.@c/** * Converts the constant in vr to the MAL type type. Conversion is done * in the vr struct. * Returns 0 on success, non-zero otherwise. */intconvertConstant(malType type, ValPtr vr){ if( vr->vtype == type) return 0; if( vr->vtype == TYPE_str){#ifdef STRUCT_ALIGNED int ll = 0; ptr d = NULL; ATOMfromstr(type, &d, &ll, vr->val.sval); if (d == NULL) { showException(SYNTAX, "convertConstant", "parse error in '%s'", vr->val.sval); VALinit(vr, type, ATOMnilptr(type)); return 1; } VALset(vr, type, d); if (ATOMextern(type) == 0) GDKfree(d);#else showException(SYNTAX, "convertConstant", "missing implementation");#endif return vr->vtype != type; } switch (type) { case TYPE_any: assert(0); case TYPE_bit: case TYPE_chr: case TYPE_sht: case TYPE_int: case TYPE_void: case TYPE_oid: case TYPE_flt: case TYPE_dbl: case TYPE_lng: VALconvert(type,vr); return vr->vtype != type; case TYPE_str: { str w=0; if( vr->vtype == TYPE_void){ vr->vtype = type; vr->val.sval = GDKstrdup(str_nil); return 0; } if( vr->vtype == TYPE_chr){ w= GDKstrdup("a"); *w = vr->val.cval[0]; } else ATOMformat(vr->vtype, VALptr(vr), &w); assert(w != NULL); vr->vtype= TYPE_str; vr->len = strlen(w); vr->val.sval= w; /* VALset(vr, type, w); does not use TYPE-str */ } return vr->vtype != type; case TYPE_bat: /* BAT variables can only be set to nil */ vr->vtype = type; vr->val.bval = 0; return 0; case TYPE_ptr: /* all coercions should be avoided to protect against memory probing */ /* if (vr->vtype == TYPE_void) { vr->vtype = type; vr->val.pval = 0; return 0; } if (ATOMcmp(vr->vtype, ATOMnilptr(vr->vtype), VALptr(vr)) == 0) { vr->vtype = type; vr->val.pval = 0; return 0; } if (vr->vtype == TYPE_int) { char buf[BUFSIZ]; int ll = 0; ptr d = NULL; snprintf(buf, BUFSIZ, "%d", vr->val.ival); (*BATatoms[type].atomFromStr) (buf, &ll, &d); if( d==0 ){ VALinit(vr, type, BATatoms[type].atomNull); return 1; } VALset(vr, type, d); if (ATOMextern(type) == 0 ) GDKfree(d); } */ return vr->vtype != type;@-Extended types are always represented as string literalsand converted to the internal storage structure.Beware that the typeFromStr routines generate storage spacefor the new value. This should be garbage collected at theend.@c default:{ int ll = 0; ptr d = NULL; str s; if( isaBatType(type)){ VALinit(vr, TYPE_bat, ATOMnilptr(TYPE_bat)); break; } /* see if an atomFromStr() function is available */ if (BATatoms[type].atomFromStr == 0) { s = getTypeName(type); showException(SYNTAX, "convertConstant", "no string coercion for '%s'", s); GDKfree(s); break; } /* if the value we're converting from is nil, the to * convert to value will also be nil */ if (ATOMcmp(vr->vtype, ATOMnilptr(vr->vtype), VALptr(vr)) == 0) { VALinit(vr, type, ATOMnilptr(type)); break; } /* if what we're converting from is not a string */ if (vr->vtype != TYPE_str) { /* an extern type */ str w = 0; /* dump the non-string atom as string in w */ ATOMformat(vr->vtype, VALptr(vr), &w); /* and try to parse it from string as the desired type */ ATOMfromstr(type, &d, &ll, w); if (d == 0) { showException(SYNTAX, "convertConstant", "parse error in '%s'", w); VALinit(vr, type, ATOMnilptr(type)); GDKfree(w); return 1; } VALset(vr, type, d); if (ATOMextern(type) == 0) GDKfree(d); GDKfree(w); } else { /* what we're converting from is a string */#ifdef STRUCT_ALIGNED ATOMfromstr(type, &d, &ll, vr->val.sval); if (d == NULL) { showException(SYNTAX, "convertConstant", "parse error in '%s'", vr->val.sval); VALinit(vr, type, ATOMnilptr(type)); return 1; } VALset(vr, type, d); if (ATOMextern(type) == 0) GDKfree(d);#else showException(SYNTAX, "convertConstant", "missing implementation");#endif } } } return vr->vtype != type;}#define MAL_VAR_WINDOW 4*MAXARGintfndConstant(MalBlkPtr mb, ValPtr cst){ int i, k; ptr p = VALget(cst); k = mb->vtop - MAL_VAR_WINDOW; if (k < 0) k = 0; for (i = mb->vtop - 1; i >= k; i--) { VarPtr v = getVar(mb, i); if (v && v->isaconstant && v->type == cst->vtype && ATOMcmp(cst->vtype, VALget(&v->value), p) == 0) return i; } return -1;}intcpyConstant(MalBlkPtr mb, VarPtr vr){ int i; ValRecord cst; VALcopy(&cst, &vr->value); i = defConstant(mb, vr->type, &cst); return i;}intdefConstant(MalBlkPtr mb, int type, ValPtr cst){ int i, k; ValPtr vr; if (cst->vtype != type){ int otype= cst->vtype; i= convertConstant(type, cst); if( i ) { str ft,tt; ft= getTypeName(otype); tt= getTypeName(type); showException(SYNTAX, "defConstant", "constant coercion error from %s to %s", ft,tt); GDKfree(ft); GDKfree(tt); mb->errors++; } else assert(cst->vtype== type); } k= fndConstant(mb,cst); if( k >= 0 ) return k; k = newTmpVariable(mb, type); isConstant(mb, k) = 1; setFixed(mb, k); vr = &getVarConstant(mb, k); *vr = *cst; /*memcpy((char *) vr, cst, sizeof(ValRecord));*/ return k;}@- Argument handlingThe number of arguments for procedures is currently limited.Furthermore, we should assure that no variable is referencedbefore being assigned.Failure to obey should mark the instruction as type-error.@cInstrPtrpushArgument(MalBlkPtr mb, InstrPtr p, int varid){ p->argv[p->argc++] = varid; if (p->argc == p->maxarg) { InstrPtr pn; int pc = 0; int space = (p->maxarg - 1) * sizeof(int) + sizeof(InstrRecord); pn = GDKmalloc(space + MAXARG * sizeof(int)); memcpy((char *) pn, (char *) p, space); pn->maxarg = p->maxarg + MAXARG; pc = getPC(mb, p); if (pc >= 0) mb->stmt[pc] = pn; GDKfree(p); p = pn; } return p;}InstrPtrsetArgument(MalBlkPtr mb, InstrPtr p, int idx, int varid){ int i; p = pushArgument(mb, p, varid); /* make space */ for (i = p->argc - 1; i > idx; i--) getArg(p, i) = getArg(p, i - 1); getArg(p, i) = varid; return p;}InstrPtrpushReturn(MalBlkPtr mb, InstrPtr p, int varid){ if (p->argv[p->retc - 1] == -1) { p->argv[p->retc - 1] = varid; return p; } p = pushArgument(mb, p, varid); p->retc++; return p;}@-Store the information of a destination variable in the signature structure ofeach instruction. This code is largely equivalent to pushArgument,but it is more efficient in searching and collecting the information.[todo]@cInstrPtrpushArgumentId(MalBlkPtr mb, InstrPtr p, str name){ int v; v = findVariable(mb, name); if (v < 0) v = newVariable(mb, name, getTypeIndex(name, -1, TYPE_any)); else GDKfree(name); return pushArgument(mb, p, v);}@-The alternative is to remove arguments from an instruction record.This is typically part of instruction constructions.@cvoiddelArgument(InstrPtr p, int idx){ int i; for (i = idx; i < p->argc - 1; i++) p->argv[i] = p->argv[i + 1]; p->argc--; if (idx < p->retc) p->retc--;}voidsetVarType(MalBlkPtr mb, int i, int tpe){ VarPtr v; v = mb->var[i]; v->type = tpe; v->gdktype = tpe <= TYPE_str ? tpe : (tpe == TYPE_any ? TYPE_void : findGDKtype(tpe));}@-Cleaning a variable type by setting it to TYPE_anypossibly invalidates all other type derivations in the program.@cvoidclrAllTypes(MalBlkPtr mb){ int i; InstrPtr p; p= getInstrPtr(mb,0); for(i=p->argc; i<mb->vtop; i++) if( !mb->var[i]->isudftype && mb->var[i]->isused && !mb->var[i]->isaconstant){ setVarType(mb,i,TYPE_any); setVarCleanup(mb,i) = FALSE; mb->var[i]->gdktype= TYPE_void; mb->var[i]->fixtype= 0; } for(i=1; i<mb->stop-1; i++){ p= getInstrPtr(mb,i); switch(p->token){ case RAISEsymbol: case CATCHsymbol: case RETURNsymbol: case LEAVEsymbol: case YIELDsymbol: case EXITsymbol: case NOOPsymbol: break; case ENDsymbol: return; default: p->token= ASSIGNsymbol; p->typechk= TYPE_UNKNOWN; p->fcn= 0; p->blk= NULL; } }}voidsetArgType(MalBlkPtr mb, InstrPtr p, int i, int tpe){ if (p->argv[i] >= mb->vsize) { GDKwarning("setArgType:array bound error\n"); return; } mb->var[getArg(p, i)]->type = tpe;}voidsetReturnArgument(InstrPtr p, int i){ setDestVar(p, i);}malTypedestinationType(MalBlkPtr mb, InstrPtr p){ if (p->argc > 0) return getVarType(mb, getDestVar(p)); return TYPE_any;}@-For polymorphic instructions we should keep around themaximal index to later allocate sufficient spacefor type resolutions maps.Beware, that we only consider the instruction polymorphicif it has an index or belongs to the signature.In other cases it merely has to be filled.@cINLINE voidsetPolymorphic(InstrPtr p, int tpe, int force){ int c1 = 0, c2 = 0; if (force == FALSE && tpe == TYPE_any) return; if (isaBatType(tpe)) { if (getHeadIndex(tpe) > 0) c1 = getHeadIndex(tpe); else if (getHeadType(tpe) == TYPE_any) c1 = 1; } if (getTailIndex(tpe) > 0) c2 = getTailIndex(tpe); else if (getTailType(tpe) == TYPE_any) c2 = 1; c1 = c1 > c2 ? c1 : c2; if (c1 > 0 && c1 >= p->polymorphic) p->polymorphic = c1 + 1;}@-Instructions are simply appended to a MAL block.It is also the place to collect information to speed-up use later on.@cvoidpushInstruction(MalBlkPtr mb, InstrPtr p){ int i; i = mb->stop; if (i + 1 >= mb->ssize) { int space = (mb->ssize + STMT_INCREMENT) * sizeof(InstrPtr); InstrPtr *newblk = (InstrPtr *) GDKzalloc(space); if (newblk == NULL) { mb->errors++; showException(MAL, "pushInstruction", "out of memory (requested: %d bytes)", space); return; } memcpy(newblk, mb->stmt, mb->stop * sizeof(InstrPtr)); mb->ssize += STMT_INCREMENT; GDKfree(mb->stmt); mb->stmt = newblk; }@-If the destination variable has not been set, introduce a temporaryvariable to hold the result instead.@c/* if (p->argv[0] < 0) p->argv[0] = newTmpVariable(mb, TYPE_any);*/ assert(p->argv[0]>=0); if (mb->stmt[i]) { /* if( getModuleId(mb->stmt[i] ) ) printf("Garbage collect statement %s.%s\n", getModuleId(mb->stmt[i]), getFunctionId(mb->stmt[i])); */ freeInstruction(mb->stmt[i]); } mb->stmt[i] = p; mb->stop++;}@-The END instruction has an optional name, which is only checkedduring parsing;@cvoidpushEndInstruction(MalBlkPtr mb){ InstrPtr p; p = newInstruction(mb, ENDsymbol); p->argc = 0; p->retc = 0; p->argv[0] = 0; pushInstruction(mb, p);}@-Property value setting.@cvoidsetVarProperty(MalBlkPtr mb, int i, str name, str op, ValPtr cst){ bit t = TRUE; if (getProps(mb,i) == NULL) getProps(mb,i) = newPropertySet(); if (cst == NULL) setProperty(getProps(mb,i), name, "", TYPE_bit, &t);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -