void parsearglist(void) { vpush((numvar) arg); // save base of current argblock #if defined(STRING_POOL) vpush((numvar) stringPool); // save stringPool base for later release strpush(idbuf); // save called function's name as arg[-1] #endif numvar *newarg = &vstack[vsptr]; // move global arg pointer to base of new block vpush(0); // initialize new arg(0) (a/k/a argc) to 0 if (sym == s_lparen) { getsym(); // eat arglist '(' while ((sym != s_rparen) && (sym != s_eof)) { #if defined(STRING_POOL) if (sym == s_quote) { vpush((numvar) stringPool); // push the string pointer parsestring(&spush); // parse it into the pool spush(0); // and terminate it getsym(); // eat closing " } else #endif vpush(getnum()); // push the value newarg[0]++; // bump the count if (sym == s_comma) getsym(); // eat arglist ',' and go around else break; } if (sym == s_rparen) getsym(); // eat the ')' else expected(M_rparen); } arg = newarg; // activate new argument frame }
///////// // // Parse and interpret a stream, and return its value // // This is used in doCommand to execute a passed-in or collected text command, // in domacrocommand() when a macro/function is called from within a parse stream, // and in runBackgroundTasks to kick off the background run. // // numvar execscript(byte scripttype, numvar scriptaddress, char *scriptname) { // save parse context parsepoint fetchmark; markparsepoint(&fetchmark); byte thesym = sym; vpush(symval); // if this is the first stream context in this invocation, // set up our error recovery point and init the value stack // otherwise we skip this to allow nested execution calls // to properly return to top // if (fetchtype == SCRIPT_NONE) { // Exceptions come here via longjmp; see bitlash-error.c switch(setjmp(env)) { case 0: break; case X_EXIT: { // POLICY: Stop all background tasks on any error // // It is not possible to be certain that continuing here will work. // Not all errors leave the interpreter in a working state. Though most do. // The conservative/deterministic choice is to stop all background tasks // and drop the user back to the command prompt. // // On the other hand, you may find this inconvenient in your application, // and may be happy taking the risk of continuing. // // In which case, comment out this line and proceed with caution. // // TODO: if the macro "onerror" exists, call it here instead. Let it "stop *". // // -br // initTaskList(); // stop all pending tasks #ifdef SOFTWARE_SERIAL_TX resetOutput(); // clean up print module #endif // Other cleanups here vinit(); // initialize the expression stack fetchtype = SCRIPT_NONE; // reset parse context fetchptr = 0L; // reset parse location // sd_up = 0; // TODO: reset file system return (numvar) -1; } // X_EXIT case } // switch } initparsepoint(scripttype, scriptaddress, scriptname); getsym(); // interpret the function text and collect its result numvar ret = getstatementlist(); returntoparsepoint(&fetchmark, 1); // now where were we? sym = thesym; symval = vpop(); return ret; }
void vinit(void) { vsptr = VSTACKLEN-1; arg = &vstack[vsptr]; // point the argblock at the stack base vpush(0); // push a 0 there so arg(0) is 0 at the top #if defined(STRING_POOL) stringPool = (char *) vstack; // stringPool starts at unused base of vstack *stringPool = 0; // make it look empty #endif }
void Compiler::gen_jsr(unsigned target) { AR gr = valloc(jobj); const JInst& jinst = *m_curr_inst; movp(gr, jinst.next, m_bbinfo->start); vpush(Val(jretAddr, gr)); gen_bb_leave(target); br(cond_none, target, m_bbinfo->start); }
void expr2_test() { int a, b; printf("expr2:\n"); vstack_ptr = vstack; vpush(1432432, 2); vstack_ptr[-2] &= ~0xffffff80; vpop(&a, &b); printf("res= %d %d\n", a, b); }
/** * Provides fine-tuned implementation for IDIV/IREM operations on IA32-compatible platforms, * in replacement of common arithmetic helper (see arith_rt.h). */ bool CodeGen::gen_a_platf(JavaByteCodes op, jtype jt) { if (jt != i32) return false; if (op != OPCODE_IDIV && op != OPCODE_IREM) { return false; } // // The method is supposed to be platform-depended, and may not have // Encoder support - leaving as-is, without implementing general // support in Encoder // vpark(eax.reg()); vpark(edx.reg()); rlock(eax); rlock(edx); Val& v1 = vstack(1, vis_imm(1)); Val& v2 = vstack(0, true); alu(alu_cmp, v2.as_opnd(), Opnd(-1)); unsigned br_normal = br(ne, 0, 0); alu(alu_cmp, v1.as_opnd(), Opnd(INT_MIN)); unsigned br_exit = NOTHING; if (op == OPCODE_IREM) { do_mov(edx, Opnd(0)); // prepare exit value for the corner case br_exit = br(eq, 0, 0); } else { do_mov(eax, v1); br_exit = br(eq, 0, 0); } patch(br_normal, ip()); do_mov(eax, v1); // // The method is supposed to be platform-depended, and may not have // Encoder support - leaving as-is, without implementing general // support in Encoder // //CDQ EncoderBase::Operands args0(RegName_EDX, RegName_EAX); ip(EncoderBase::encode(ip(), Mnemonic_CDQ, args0)); //IDIV EncoderBase::Operands args(RegName_EDX, RegName_EAX, devirt(v2.reg(), i32)); ip(EncoderBase::encode(ip(), Mnemonic_IDIV, args)); patch(br_exit, ip()); vpop(); vpop(); vpush(op == OPCODE_IREM ? edx : eax); runlock(eax); runlock(edx); return true; }
// call a macro and push its return value on the stack // void domacrocall(int macroaddress) { if (macroaddress >= 0) { parsearglist(); byte thesym = sym; // save sym for restore vpush(symval); // and symval char *fetchmark = fetchptr; // save the current parse pointer // call the macro calleeprommacro(findend(macroaddress)); // register the macro into the parser stream getsym(); // fetch its first symbol numvar ret = getstatementlist(); // parse and execute the macro code here // if (sym != s_eof) expected(M_eof); // restore parsing context so we can resume cleanly symval = vpop(); // restore symval sym = thesym; // restore saved sym releaseargblock(); // drop the args fetchptr = fetchmark; // restore pointer primec(); // and inchar vpush(ret); // send back our return value } }
///////// // // Call a Bitlash script function and push its return value on the stack // void callscriptfunction(byte scripttype, numvar scriptaddress) { // note on function name management // // we get here with the name of the function we want to call in global idbuf. // parsearglist() pushes a copy of idbuf into the string pool, so // the function's name is the first data in the string pool slab // that will be deallocated when the function returns // // we can refer to this copy of the function's name via the callername macro // parsearglist(); numvar ret = execscript(scripttype, scriptaddress, calleename); releaseargblock(); vpush(ret); }
pointer EUSPINHOLE_CAMERA_MODEL_PROJECT_3D_TO_PIXEL(register context *ctx,int n,pointer *argv) { ckarg(2); image_geometry::PinholeCameraModel *pcm = (image_geometry::PinholeCameraModel *)(intval(argv[0])); if(!isvector(argv[1])) error(E_NOVECTOR); eusfloat_t *pos = argv[1]->c.fvec.fv; cv::Point3d xyz = cv::Point3d(pos[0]/1000.0, pos[1]/1000.0, pos[2]/1000.0); cv::Point2d uv = pcm->project3dToPixel(xyz); pointer vs = makefvector(2); vpush(vs); vs->c.fvec.fv[0] = uv.x; vs->c.fvec.fv[1] = uv.y; vpop(); return(vs); }
pointer EUSPINHOLE_CAMERA_MODEL_PROJECT_PIXEL_TO_3DRAY(register context *ctx,int n,pointer *argv) { ckarg(2); image_geometry::PinholeCameraModel *pcm = (image_geometry::PinholeCameraModel *)(intval(argv[0])); if(!isvector(argv[1])) error(E_NOVECTOR); eusfloat_t *pixel = argv[1]->c.fvec.fv; cv::Point2d uv = cv::Point2d(pixel[0], pixel[1]); cv::Point3d xyz = pcm->projectPixelTo3dRay(uv); pointer vs = makefvector(3); vpush(vs); vs->c.fvec.fv[0] = xyz.x; vs->c.fvec.fv[1] = xyz.y; vs->c.fvec.fv[2] = xyz.z; vpop(); return(vs); }
// Get a statement void getstatement(void) { #if !defined(TINY85) chkbreak(); #endif if (sym == s_while) { // at this point sym is pointing at s_while, before the conditional expression // save fetchptr so we can restart parsing from here as the while iterates char *fetchmark = fetchptr; for (;;) { fetchptr = fetchmark; // restore to mark primec(); // set up for mr. getsym() getsym(); // fetch the start of the conditional if (!getnum()) { //longjmp(env, X_EXIT); // get the conditional; exit on false sym = s_eof; // we're finished here. move along. return; } if (sym != s_colon) expectedchar(':'); getsym(); // eat : getstatementlist(); } } else if (sym == s_if) { getsym(); // fetch the start of the conditional if (!getnum()) { //longjmp(env, X_EXIT); // get the conditional; exit on false sym = s_eof; return; } if (sym != s_colon) expectedchar(':'); getsym(); // eat : getstatementlist(); } #if SKETCH // The switch statement: call one of N macros based on a selector value // switch <numval>: macroid1, macroid2,.., macroidN // numval < 0: numval = 0 // numval > N: numval = N else if (sym == s_switch) { getsym(); // eat "switch" numvar selector = getnum(); // evaluate the switch value if (selector < 0) selector = 0; if (sym != s_colon) expectedchar(':'); // we sit before the first macroid // scan and discard the <selector>'s worth of macro ids // that sit before the one we want for (;;) { getsym(); // get an id, sets symval to its eeprom addr as a side effect if (sym != s_macro) expected (6); // TODO: define M_macro instead of 6 getsym(); // eat id, get separator; assume symval is untouched if ((sym == s_semi) || (sym == s_eof)) break; // last case is default so we exit always if (sym != s_comma) expectedchar(','); if (!selector) break; // ok, this is the one we want to execute selector--; // one down... } // call the macro whose addr is squirreled in symval all this time // on return, the parser is ready to pick up where we left off doMacroCall(symval); // scan past the rest of the unused switch options, if any // TODO: syntax checking for non-chosen options could be made much tighter at the cost of some space while ((sym != s_semi) && (sym != s_eof)) getsym(); // scan to end of statement without executing } #endif else if ((sym == s_macro) || (sym == s_undef)) { // macro def or ref getsym(); // scan past macro name to next symbol: ; or := if (sym == s_define) { // macro definition: macroid := strvalue // to define the macro, we need to copy the id somewhere on the stack // to avoid having this local buffer in every getstatement stack frame, // we break out defineMacro here to a separate function that only eats that // stack in the case that a macro is being defined #ifdef TINY85 unexpected(M_defmacro); #else defineMacro(); #endif } else if ((sym == s_semi) || (sym == s_eof)) { // valid macro reference: let's call it #if SKETCH doMacroCall(symval); // parseid stashes the macro address in symval #else char op = sym; // save sym for restore expval = findKey(idbuf); // assumes id in idbuf isn't clobbered since getsym() above if (expval >= 0) { char *fetchmark = fetchptr; // save the current parse pointer // call the macro calleeprommacro(findend(expval)); // register the macro into the parser stream getsym(); getstatementlist(); // parse and execute the macro code here if (sym != s_eof) expected(M_eof); // restore parsing context so we can resume cleanly fetchptr = fetchmark; // restore pointer primec(); // and inchar sym = op; // restore saved sym: s_semi or s_eof } else unexpected(M_id); #endif } else expectedchar(';'); //else getexpression(); // assume it was macro1+32+macro2... } else if (sym == s_run) { // run macroname getsym(); if (sym != s_macro) unexpected(M_id); #if 0 // address of macroid is in symval via parseid startTask(kludge(symval)); getsym(); #else // address of macroid is in symval via parseid // check for [,snoozeintervalms] getsym(); // eat macroid to check for comma; symval untouched if (sym == s_comma) { vpush(symval); getsym(); // eat the comma getnum(); // get a number or else startTask(kludge(vpop()), expval); } else startTask(kludge(symval), 0); #endif } else if (sym == s_stop) { getsym(); if (sym == s_mul) { // stop * stops all tasks initTaskList(); getsym(); } else if ((sym == s_semi) || (sym == s_eof)) { if (background) stopTask(curtask); // stop with no args stops the current task IF we're in back else initTaskList(); // in foreground, stop all } else stopTask(getnum()); } else if (sym == s_boot) reboot(); #if !defined(TINY85) else if (sym == s_rm) { // rm "sym" or rm * getsym(); if (sym == s_macro) { eraseentry(idbuf); } else if (sym == s_mul) nukeeeprom(); else expected(M_id); getsym(); } else if (sym == s_ps) showTaskList(); else if (sym == s_peep) { getsym(); cmd_peep(); } else if (sym == s_ls) { getsym(); cmd_ls(); } else if (sym == s_help) { getsym(); cmd_help(); } else if (sym == s_print) { getsym(); cmd_print(); } #endif #ifdef HEX_UPLOAD // a line beginning with a colon is treated as a hex record // containing data to upload to eeprom // // TODO: verify checksum // else if (sym == s_colon) { // fetchptr points at the byte count byte byteCount = gethex(2); // 2 bytes byte count int addr = gethex(4); // 4 bytes address byte recordType = gethex(2); // 2 bytes record type; now fetchptr -> data if (recordType == 1) reboot(); // reboot on EOF record (01) if (recordType != 0) return; // we only handle the data record (00) if (addr == 0) nukeeeprom(); // auto-clear eeprom on write to 0000 while (byteCount--) eewrite(addr++, gethex(2)); // update the eeprom gethex(2); // discard the checksum getsym(); // and re-prime the parser } #endif else { getexpression(); } }
// Get a statement numvar getstatement(void) { numvar retval = 0; //char *fetchmark; numvar fetchmark; chkbreak(); if (sym == s_while) { // at this point sym is pointing at s_while, before the conditional expression // save fetchptr so we can restart parsing from here as the while iterates //fetchmark = fetchptr; fetchmark = markparsepoint(); for (;;) { //fetchptr = fetchmark; // restore to mark //primec(); // set up for mr. getsym() returntoparsepoint(fetchmark, 0); getsym(); // fetch the start of the conditional if (getnum()) { retval = getstatement(); if (sym == s_returning) break; // exit if we caught a return } else { skipstatement(); break; } } } else if (sym == s_if) { getsym(); // eat "if" if (getnum()) { retval = getstatement(); if (sym == s_else) { getsym(); // eat "else" skipstatement(); } } else { skipstatement(); if (sym == s_else) { getsym(); // eat "else" retval = getstatement(); } } } else if (sym == s_lcurly) { getsym(); // eat "{" while ((sym != s_eof) && (sym != s_returning) && (sym != s_rcurly)) retval = getstatement(); if (sym == s_rcurly) getsym(); // eat "}" } else if (sym == s_return) { getsym(); // eat "return" if ((sym != s_eof) && (sym != s_semi)) retval = getnum(); sym = s_returning; // signal we're returning up the line } else if (sym == s_switch) retval = getswitchstatement(); else if (sym == s_function) cmd_function(); else if (sym == s_run) { // run macroname getsym(); if ((sym != s_script_eeprom) && (sym != s_script_progmem) && (sym != s_script_file)) unexpected(M_id); // address of macroid is in symval via parseid // check for [,snoozeintervalms] getsym(); // eat macroid to check for comma; symval untouched if (sym == s_comma) { vpush(symval); getsym(); // eat the comma getnum(); // get a number or else startTask(vpop(), expval); } else startTask(symval, 0); } else if (sym == s_stop) { getsym(); if (sym == s_mul) { // stop * stops all tasks initTaskList(); getsym(); } else if ((sym == s_semi) || (sym == s_eof)) { if (background) stopTask(curtask); // stop with no args stops the current task IF we're in back else initTaskList(); // in foreground, stop all } else stopTask(getnum()); } else if (sym == s_boot) reboot(); else if (sym == s_rm) { // rm "sym" or rm * getsym(); if (sym == s_script_eeprom) { eraseentry(idbuf); } else if (sym == s_mul) nukeeeprom(); else if (sym != s_undef) expected(M_id); getsym(); } else if (sym == s_ps) { getsym(); showTaskList(); } else if (sym == s_peep) { getsym(); cmd_peep(); } else if (sym == s_ls) { getsym(); cmd_ls(); } else if (sym == s_help) { getsym(); cmd_help(); } else if (sym == s_print) { getsym(); cmd_print(); } else if (sym == s_semi) { ; } // ;) #ifdef HEX_UPLOAD // a line beginning with a colon is treated as a hex record // containing data to upload to eeprom // // TODO: verify checksum // else if (sym == s_colon) { // fetchptr points at the byte count byte byteCount = gethex(2); // 2 bytes byte count int addr = gethex(4); // 4 bytes address byte recordType = gethex(2); // 2 bytes record type; now fetchptr -> data if (recordType == 1) reboot(); // reboot on EOF record (01) if (recordType != 0) return; // we only handle the data record (00) if (addr == 0) nukeeeprom(); // auto-clear eeprom on write to 0000 while (byteCount--) eewrite(addr++, gethex(2)); // update the eeprom gethex(2); // discard the checksum getsym(); // and re-prime the parser } #endif else getexpression(); if (sym == s_semi) getsym(); // eat trailing ';' return retval; }
// // Recursive descent parser, old-school style. // void getfactor(void) { numvar thesymval = symval; byte thesym = sym; getsym(); // eat the sym we just saved switch (thesym) { case s_nval: vpush(thesymval); break; case s_nvar: if (sym == s_equals) { // assignment, push is after the break; getsym(); assignVar(thesymval, getnum()); } else if (sym == s_incr) { // postincrement nvar++ vpush(getVar(thesymval)); assignVar(thesymval, getVar(thesymval) + 1); getsym(); break; } else if (sym == s_decr) { // postdecrement nvar-- vpush(getVar(thesymval)); assignVar(thesymval, getVar(thesymval) - 1); getsym(); break; } vpush(getVar(thesymval)); // both assignment and reference get pushed here break; case s_nfunct: dofunctioncall(thesymval); // get its value onto the stack break; // Script-function-returning-value used as a factor case s_script_eeprom: // macro returning value callscriptfunction(SCRIPT_EEPROM, findend(thesymval)); break; case s_script_progmem: callscriptfunction(SCRIPT_PROGMEM, thesymval); break; case s_script_file: callscriptfunction(SCRIPT_FILE, (numvar) 0); // name implicitly in idbuf! break; case s_apin: // analog pin reference like a0 if (sym == s_equals) { // digitalWrite or analogWrite getsym(); analogWrite(thesymval, getnum()); vpush(expval); } else vpush(analogRead(thesymval)); break; case s_dpin: // digital pin reference like d1 if (sym == s_equals) { // digitalWrite or analogWrite getsym(); digitalWrite(thesymval, getnum()); vpush(expval); } else vpush(digitalRead(thesymval)); break; case s_incr: if (sym != s_nvar) expected(M_var); assignVar(symval, getVar(symval) + 1); vpush(getVar(symval)); getsym(); break; case s_decr: // pre decrement if (sym != s_nvar) expected(M_var); assignVar(symval, getVar(symval) - 1); vpush(getVar(symval)); getsym(); break; case s_arg: // arg(n) - argument value if (sym != s_lparen) expectedchar(s_lparen); getsym(); // eat '(' vpush(getarg(getnum())); if (sym != s_rparen) expectedchar(s_rparen); getsym(); // eat ')' break; case s_lparen: // expression in parens getexpression(); if (exptype != s_nval) expected(M_number); if (sym != s_rparen) missing(M_rparen); vpush(expval); getsym(); // eat the ) break; // // The Family of Unary Operators, which Bind Most Closely to their Factor // case s_add: // unary plus (like +3) is kind of a no-op getfactor(); // scan a factor and leave its result on the stack break; // done case s_sub: // unary minus (like -3) getfactor(); vpush(-vpop()); // similar to above but we adjust the stack value break; case s_bitnot: getfactor(); vpush(~vpop()); break; case s_logicalnot: getfactor(); vpush(!vpop()); break; case s_bitand: // &var gives address-of-var; ¯o gives eeprom address of macro if (sym == s_nvar) vpush((numvar) &vars[symval]); else if (sym == s_script_eeprom) vpush(symval); else expected(M_var); getsym(); // eat the var reference break; case s_mul: // *foo is contents-of-address-foo; *foo=bar is byte poke assignment /***** // what is really acceptable for an lvalue here? ;) // *y = 5 is failing now by assigning 5 to y before the * is dereferenced // due to calling getfactor // everything else works :( *****/ getfactor(); #if 0 if (sym == s_equals) { getsym(); // eat '=' getexpression(); * (volatile byte *) vpop() = (byte) expval; vpush((numvar) (byte) expval); } else #endif vpush((numvar) (* (volatile byte *) vpop())); break; default: unexpected(M_number); } }
void vop(byte op) { numvar x,y; x = vpop(); y = vpop(); switch (op) { case s_add: vpush(y + x); break; case s_sub: vpush(y - x); break; case s_mul: vpush(y * x); break; case s_div: vpush(y / x); break; case s_mod: vpush(y % x); break; case s_lt: vpush(y < x); break; case s_gt: vpush(y > x); break; case s_le: vpush(y <= x); break; case s_ge: vpush(y >= x); break; case s_logicalne: vpush(y != x); break; case s_logicaland: vpush(y && x); break; case s_logicalor: vpush(y || x); break; case s_logicaleq: vpush(y == x); break; case s_bitor: vpush(y | x); break; case s_bitand: vpush(y & x); break; case s_xor: vpush(y ^ x); break; case s_shiftleft: vpush(y << x); break; case s_shiftright: vpush(y >> x); break; default: unexpected(M_op); } }
void CodeGen::gen_a(JavaByteCodes op, jtype jt) { if (gen_a_platf(op, jt)) { return; } if (gen_a_generic(op, jt)) { return; } if (is_f(jt) && gen_a_f(op, jt)) { return; } if (jt == i32 && gen_a_i32(op)) { return; } unsigned stackFix = 0; bool shft = op == OPCODE_ISHL || op == OPCODE_ISHR || op == OPCODE_IUSHR; const CallSig* rcs = NULL; if (is_f(jt)) { assert(jt == dbl64 || jt == flt32); char * helper = NULL; bool is_dbl = jt == dbl64; if (op == OPCODE_INEG) { SYNC_FIRST(static const CallSig cs_dbl(CCONV_STDCALL, dbl64, dbl64)); SYNC_FIRST(static const CallSig cs_flt(CCONV_STDCALL, flt32, flt32)); rcs = is_dbl? &cs_dbl : &cs_flt; stackFix = gen_stack_to_args(true, *rcs, 0, 1); helper = is_dbl ? (char*)&rt_h_neg_dbl64 : (char*)&rt_h_neg_flt32; gen_call_novm(*rcs, helper, 1); runlock(*rcs); } else { //if (m_jframe->dip(1).stype == st_imm && ) SYNC_FIRST(static const CallSig cs_dbl(CCONV_STDCALL, dbl64, dbl64, dbl64, i32)); SYNC_FIRST(static const CallSig cs_flt(CCONV_STDCALL, flt32, flt32, flt32, i32)); rcs = is_dbl? &cs_dbl : &cs_flt; stackFix = gen_stack_to_args(true, *rcs, 0, 2); helper = is_dbl ? (char*)&rt_h_dbl_a : (char*)&rt_h_flt_a; gen_call_novm(*rcs, helper, 2, op); runlock(*rcs); } } else if (jt==i64) { if (op == OPCODE_INEG) { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i64, i64)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 1); gen_call_novm(*rcs, (void*)&rt_h_neg_i64, 1); runlock(*rcs); } else if (shft) { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i64, i64, i32, i32)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 2); gen_call_novm(*rcs, (void*)&rt_h_i64_shift, 2, op); runlock(*rcs); } else { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i64, i64, i64, i32)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 2); gen_call_novm(*rcs, (void*)&rt_h_i64_a, 2, op); runlock(*rcs); } } else { assert(jt==i32); if (op == OPCODE_INEG) { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i32, i32)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 1); gen_call_novm(*rcs, (void*)&rt_h_neg_i32, 1); runlock(*rcs); } else if (op == OPCODE_IADD || op == OPCODE_ISUB) { const Val& op2 = vstack(0); vpop(); rlock(op2); const Val& op1 = vstack(0); vpop(); rlock(op1); AR ar = valloc(i32); Opnd reg(i32, ar); //TODO: may eliminate additional register allocation mov(reg, op1.as_opnd()); alu(op == OPCODE_IADD ? alu_add : alu_sub, reg, op2.as_opnd()); runlock(op1); runlock(op2); vpush(Val(i32, ar)); return; } else { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i32, i32, i32, i32)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 2); gen_call_novm(*rcs, (void*)&rt_h_i32_a, 2, op); runlock(*rcs); } } assert(rcs != NULL); gen_save_ret(*rcs); if (stackFix != 0) { alu(alu_sub, sp, stackFix); } }
bool CodeGen::gen_a_generic(JavaByteCodes op, jtype jt) { if (op == OPCODE_INEG) { return false; // later } if (jt == i32) { bool v2_imm = vis_imm(0); if (v2_imm && (op == OPCODE_ISHL || op == OPCODE_ISHL || op == OPCODE_IUSHR)) { // accept it } /*else if (v2_imm && (op == OPCODE_IMUL || op == OPCODE_IDIV)) { // accept it } else if (op == OPCODE_IMUL) { // accept it }*/ else if (op == OPCODE_IADD || op == OPCODE_ISUB) { // accept it } else if (op == OPCODE_IOR || op == OPCODE_IAND || op == OPCODE_IXOR) { // accept it } else if (vis_imm(0) && m_jframe->size()>1 && vis_imm(1)) { // accept it } else { return false; } } else if (is_f(jt)) { if (op != OPCODE_IADD && op != OPCODE_ISUB && op != OPCODE_IMUL && op != OPCODE_IDIV) { return false; } } else { return false; } bool is_dbl = jt == dbl64; unsigned v1_depth = is_dbl?2:1; if (vis_imm(v1_depth) && vis_imm(0)) { const Val& v1 = m_jframe->dip(v1_depth); const Val& v2 = m_jframe->dip(0); Val res; if (jt==dbl64) { double d = rt_h_dbl_a(v1.dval(), v2.dval(), op); res = Val(d); } else if (jt==flt32) { float f = rt_h_flt_a(v1.fval(), v2.fval(), op); res = Val(f); } else { assert(jt==i32); int i = rt_h_i32_a(v1.ival(), v2.ival(), op); res = Val(i); } vpop(); vpop(); vpush(res); return true; } // if v1.is_imm() && v2.is_imm() const Val& v1 = vstack(v1_depth, true); Opnd res = v1.as_opnd(); if (rrefs(v1.reg()) > 1) { rlock(v1); AR ar = valloc(jt); runlock(v1); Opnd reg(jt, ar); mov(reg, v1.as_opnd()); res = reg; } rlock(res); rlock(v1); const Val& v2 = m_jframe->dip(0); /* if (false )v2. #ifdef _IA32_ // on IA32 can use address in a displacement alu(to_alu(op), v1, ar_x, (int)v2.addr()); #else AR addr = valloc(jobj); rlock(addr); movp(addr, v2.addr()); alu_mem(jt, to_alu(op), r1, addr); runlock(addr); #endif } else */ if(v2.is_mem()) { // Everyone can do 'reg, mem' operation alu(to_alu(op), res, v2.as_opnd()); } else if(v2.is_imm() && jt==i32) { // 'reg, imm' is only for i32 operations alu(to_alu(op), res, v2.ival()); } else { Opnd v2 = vstack(0, true).as_opnd(); alu(to_alu(op), res, v2); } vpop(); vpop(); runlock(v1); runlock(res); vpush(res); return true; }
// Get a statement numvar getstatement(void) { numvar retval = 0; char *fetchmark; chkbreak(); //#define LINEMODE #ifdef LINEMODE if (sym == s_while) { // at this point sym is pointing at s_while, before the conditional expression // save fetchptr so we can restart parsing from here as the while iterates char *fetchmark = fetchptr; for (;;) { fetchptr = fetchmark; // restore to mark primec(); // set up for mr. getsym() getsym(); // fetch the start of the conditional if (!getnum()) { //longjmp(env, X_EXIT); // get the conditional; exit on false sym = s_eof; // we're finished here. move along. return; } if (sym != s_colon) expectedchar(':'); getsym(); // eat : getstatementlist(); } } else if (sym == s_if) { getsym(); // fetch the start of the conditional if (!getnum()) { //longjmp(env, X_EXIT); // get the conditional; exit on false sym = s_eof; return; } if (sym != s_colon) expectedchar(':'); getsym(); // eat : getstatementlist(); } // The switch statement: call one of N macros based on a selector value // switch <numval>: macroid1, macroid2,.., macroidN // numval < 0: numval = 0 // numval > N: numval = N else if (sym == s_switch) { getsym(); // eat "switch" numvar selector = getnum(); // evaluate the switch value if (selector < 0) selector = 0; if (sym != s_colon) expectedchar(':'); // we sit before the first macroid // scan and discard the <selector>'s worth of macro ids // that sit before the one we want for (;;) { getsym(); // get an id, sets symval to its eeprom addr as a side effect if (sym != s_macro) expected (6); // TODO: define M_macro instead of 6 getsym(); // eat id, get separator; assume symval is untouched if ((sym == s_semi) || (sym == s_eof)) break; // last case is default so we exit always if (sym != s_comma) expectedchar(','); if (!selector) break; // ok, this is the one we want to execute selector--; // one down... } // call the macro whose addr is squirreled in symval all this time // on return, the parser is ready to pick up where we left off domacrocall(symval); // scan past the rest of the unused switch options, if any // TODO: syntax checking for non-chosen options could be made much tighter at the cost of some space while ((sym != s_semi) && (sym != s_eof)) getsym(); // scan to end of statement without executing } #else // new statement handling if (sym == s_while) { // at this point sym is pointing at s_while, before the conditional expression // save fetchptr so we can restart parsing from here as the while iterates fetchmark = fetchptr; for (;;) { fetchptr = fetchmark; // restore to mark primec(); // set up for mr. getsym() getsym(); // fetch the start of the conditional if (getnum()) { retval = getstatement(); if (sym == s_returning) break; // exit if we caught a return } else { skipstatement(); break; } } } else if (sym == s_if) { getsym(); // eat "if" if (getnum()) { retval = getstatement(); if (sym == s_else) { getsym(); // eat "else" skipstatement(); } } else { skipstatement(); if (sym == s_else) { getsym(); // eat "else" retval = getstatement(); } } } else if (sym == s_lcurly) { getsym(); // eat "{" while ((sym != s_eof) && (sym != s_returning) && (sym != s_rcurly)) retval = getstatement(); if (sym == s_rcurly) getsym(); // eat "}" } else if (sym == s_return) { getsym(); // eat "return" if ((sym != s_eof) && (sym != s_semi)) retval = getnum(); sym = s_returning; // signal we're returning up the line } else if (sym == s_switch) retval = getswitchstatement(); else if (sym == s_function) cmd_function(); #endif else if (sym == s_run) { // run macroname getsym(); if (sym != s_macro) unexpected(M_id); // address of macroid is in symval via parseid // check for [,snoozeintervalms] getsym(); // eat macroid to check for comma; symval untouched if (sym == s_comma) { vpush(symval); getsym(); // eat the comma getnum(); // get a number or else startTask(kludge(vpop()), expval); } else startTask(kludge(symval), 0); } else if (sym == s_stop) { getsym(); if (sym == s_mul) { // stop * stops all tasks initTaskList(); getsym(); } else if ((sym == s_semi) || (sym == s_eof)) { if (background) stopTask(curtask); // stop with no args stops the current task IF we're in back else initTaskList(); // in foreground, stop all } else stopTask(getnum()); } else if (sym == s_boot) reboot(); #if !defined(TINY85) else if (sym == s_rm) { // rm "sym" or rm * getsym(); if (sym == s_macro) { eraseentry(idbuf); } else if (sym == s_mul) nukeeeprom(); else if (sym != s_undef) expected(M_id); getsym(); } else if (sym == s_ps) { getsym(); showTaskList(); } else if (sym == s_peep) { getsym(); cmd_peep(); } else if (sym == s_ls) { getsym(); cmd_ls(); } else if (sym == s_help) { getsym(); cmd_help(); } else if (sym == s_print) { getsym(); cmd_print(); } else if (sym == s_semi) { ; } // ;) #endif #ifdef HEX_UPLOAD // a line beginning with a colon is treated as a hex record // containing data to upload to eeprom // // TODO: verify checksum // else if (sym == s_colon) { // fetchptr points at the byte count byte byteCount = gethex(2); // 2 bytes byte count int addr = gethex(4); // 4 bytes address byte recordType = gethex(2); // 2 bytes record type; now fetchptr -> data if (recordType == 1) reboot(); // reboot on EOF record (01) if (recordType != 0) return; // we only handle the data record (00) if (addr == 0) nukeeeprom(); // auto-clear eeprom on write to 0000 while (byteCount--) eewrite(addr++, gethex(2)); // update the eeprom gethex(2); // discard the checksum getsym(); // and re-prime the parser } #endif else getexpression(); if (sym == s_semi) getsym(); // eat trailing ';' return retval; }
int main() { int type; double op2; char tmp; char s[MAXOP]; while ((type = getop(s)) != EOF) { switch (type) { case NUMBER: push(atof(s)); break; case VARIABLE: push(var[s[0] - 'a']); vpush(s[0]); break; case '=': tmp = vpop(); duplicate_stack_top(); var[tmp - 'a'] = pop(); break; case '+': push(pop() + pop()); break; case '*': push(pop() * pop()); break; case '-': op2 = pop(); push(pop() - op2); break; case '/': op2 = pop(); if (op2 != 0.0) push(pop() / op2); else printf("error: zero divisor\n"); break; case '%': op2 = pop(); push((int)pop() % (int)op2); break; case 'S': push(sin(pop())); break; case 'E': push(exp(pop())); break; case 'P': op2 = pop(); push(pow(pop(),op2)); break; case '?': print_stack_top(); break; case '~': swap_top(); break; case '#': duplicate_stack_top(); break; case '@': clear(); break; case '\n': var['z' - 'a'] = pop(); printf("\t%.8g\n", var['z' - 'a']); break; default: printf("error: unknown command %s\n", s); break; } } return 0; }