/* store * * Saves the contents of "primary" into a memory cell, either directly * or indirectly (at the address given in the alternate register). */ SC_FUNC void store(value *lval) { symbol *sym; sym=lval->sym; if (lval->ident==iARRAYCELL) { /* store at address in ALT */ stgwrite("\tstor.i\n"); code_idx+=opcodes(1); } else if (lval->ident==iARRAYCHAR) { /* store at address in ALT */ stgwrite("\tstrb.i "); outval(sCHARBITS/8,TRUE,TRUE); /* write one or two bytes */ code_idx+=opcodes(1)+opargs(1); } else if (lval->ident==iREFERENCE) { assert(sym!=NULL); if (sym->vclass==sLOCAL) stgwrite("\tsref.s.pri "); else stgwrite("\tsref.pri "); outval(sym->addr,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); } else { assert(sym!=NULL); markusage(sym,uWRITTEN); if (sym->vclass==sLOCAL) stgwrite("\tstor.s.pri "); else stgwrite("\tstor.pri "); outval(sym->addr,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); } /* if */ }
SC_FUNC void fillarray(symbol *sym,cell size,cell value) { ldconst(value,sPRI); /* load value in PRI */ assert(sym!=NULL); /* the symbol can be a local array, a global array, or an array * that is passed by reference. */ if (sym->ident==iREFARRAY) { /* reference to an array; currently this is always a local variable */ assert(sym->vclass==sLOCAL); /* symbol must be stack relative */ stgwrite("\tload.s.alt "); } else { /* a local or global array */ if (sym->vclass==sLOCAL) stgwrite("\taddr.alt "); else stgwrite("\tconst.alt "); } /* if */ outval(sym->addr,TRUE); markusage(sym,uWRITTEN); assert(size>0); stgwrite("\tfill "); outval(size,TRUE); code_idx+=opcodes(2)+opargs(2); }
/* * Call specified function */ SC_FUNC void ffcall(symbol *sym,const char *label,int numargs) { char symname[2*sNAMEMAX+16]; char aliasname[sNAMEMAX+1]; int wasAlias = 0; assert(sym!=NULL); assert(sym->ident==iFUNCTN); if (sc_asmfile) funcdisplayname(symname,sym->name); if ((sym->usage & uNATIVE)!=0) { /* reserve a SYSREQ id if called for the first time */ assert(label==NULL); stgwrite("\tsysreq.c "); if (sc_status==statWRITE && (sym->usage & uREAD)==0 && sym->addr>=0) sym->addr=ntv_funcid++; /* Look for an alias */ if (lookup_alias(aliasname, sym->name)) { symbol *asym = findglb(aliasname, sGLOBAL); if (asym && asym->ident==iFUNCTN && ((sym->usage & uNATIVE) != 0)) { sym = asym; if (sc_status==statWRITE && (sym->usage & uREAD)==0 && sym->addr>=0) { sym->addr=ntv_funcid++; markusage(sym, uREAD); } } } outval(sym->addr,FALSE); if (sc_asmfile) { stgwrite("\t; "); stgwrite(symname); } /* if */ stgwrite("\n"); /* write on a separate line, to mark a sequence point for the peephole optimizer */ stgwrite("\tstack "); outval((numargs+1)*sizeof(cell), TRUE); code_idx+=opcodes(2)+opargs(2); } else { /* normal function */ stgwrite("\tcall "); if (label!=NULL) { stgwrite("l."); stgwrite(label); } else { stgwrite(sym->name); } /* if */ if (sc_asmfile && (label!=NULL || (!isalpha(sym->name[0]) && sym->name[0]!='_' && sym->name[0]!=sc_ctrlchar))) { stgwrite("\t; "); stgwrite(symname); } /* if */ stgwrite("\n"); code_idx+=opcodes(1)+opargs(1); } /* if */ }
// function value -> pri void load_glbfn(symbol *sym) { assert(sym->ident == iFUNCTN); assert(!(sym->usage & uNATIVE)); stgwrite("\tldgfn.pri "); stgwrite(sym->name); stgwrite("\n"); code_idx += opcodes(1) + opargs(1); if (sc_status != statSKIP) markusage(sym, uREAD); }
/* rvalue * * Generate code to get the value of a symbol into "primary". */ void rvalue(value *lval) { symbol *sym; sym=lval->sym; if (lval->ident==iARRAYCELL) { /* indirect fetch, address already in PRI */ load_i(); } else if (lval->ident==iARRAYCHAR) { /* indirect fetch of a character from a pack, address already in PRI */ stgwrite("\tlodb.i "); outval(sCHARBITS/8,TRUE); /* read one or two bytes */ code_idx+=opcodes(1)+opargs(1); } else if (lval->ident==iREFERENCE) { /* indirect fetch, but address not yet in PRI */ assert(sym!=NULL); assert(sym->vclass==sLOCAL);/* global references don't exist in Pawn */ if (sym->vclass==sLOCAL) stgwrite("\tlref.s.pri "); else stgwrite("\tlref.pri "); outval(sym->addr,TRUE); markusage(sym,uREAD); code_idx+=opcodes(1)+opargs(1); } else if (lval->ident==iACCESSOR) { invoke_getter(lval->accessor); lval->ident=iEXPRESSION; lval->accessor=NULL; } else { /* direct or stack relative fetch */ assert(sym!=NULL); if (sym->vclass==sLOCAL) stgwrite("\tload.s.pri "); else stgwrite("\tload.pri "); outval(sym->addr,TRUE); markusage(sym,uREAD); code_idx+=opcodes(1)+opargs(1); } /* if */ }
void invoke_getter(methodmap_method_t *method) { if (!method->getter) { error(149, method->name); return; } // sysreq.n N 1 // stack 8 pushreg(sPRI); ffcall(method->getter, NULL, 1); if (sc_status != statSKIP) markusage(method->getter, uREAD); }
void invoke_setter(methodmap_method_t *method, int save) { if (!method->setter) { error(152, method->name); return; } if (save) pushreg(sPRI); pushreg(sPRI); pushreg(sALT); ffcall(method->setter, NULL, 2); if (save) popreg(sPRI); if (sc_status != statSKIP) markusage(method->setter, uREAD); }
/* Get the address of a symbol into the primary or alternate register (used * for arrays, and for passing arguments by reference). */ SC_FUNC void address(symbol *sym,regid reg) { assert(sym!=NULL); assert(reg==sPRI || reg==sALT); /* the symbol can be a local array, a global array, or an array * that is passed by reference. */ if (sym->ident==iREFARRAY || sym->ident==iREFERENCE) { /* reference to a variable or to an array; currently this is * always a local variable */ switch (reg) { case sPRI: stgwrite("\tload.s.pri "); break; case sALT: stgwrite("\tload.s.alt "); break; } /* switch */ } else { /* a local array or local variable */ switch (reg) { case sPRI: if (sym->vclass==sLOCAL) stgwrite("\taddr.pri "); else stgwrite("\tconst.pri "); break; case sALT: if (sym->vclass==sLOCAL) stgwrite("\taddr.alt "); else stgwrite("\tconst.alt "); break; } /* switch */ } /* if */ outval(sym->addr,TRUE,TRUE); markusage(sym,uREAD); code_idx+=opcodes(1)+opargs(1); }