// javascript basic interpreter 2019 // javascript basic interpreter 2019 // 10/11/2019 // global data var running = false; var stepflag=false; //?? var stepcount=1; //?? var timestamps = new Array(); //?? // subroutines var subr_depth = 0; var subr_stack = new Array(); // return values var executed = new Array(); // whether line was executed var symbolsAddr = new Array(); // address of symbol var symbolsWidth = new Array(); var symbolsValue = new Array(); var symbolNames = new Array(); var tidyprog = new Array(); var regsarraytxt = new Array(); var milliseconds =0; var FastForward = 2; // ??????????????????????????????? var progtext; var maxpc; var pc; // current line number // new var SelState = 0; //=========================================DATA //==============================Interpreter================================== var progcount = -1;// position in prog 0- var looptop = 0;// position in prog of start of loop var action;// output e.g. 01100000 var errorpc=0; var forreg = new Array(); // address of for variable. var forwidth = new Array(); // width of for variable. if 16 then forreg must be even. var forvalue = 0; var forlimit = new Array(); var for_stack = new Array(); var forregn; var fordepth = 0; var time = 9999; var distance=0.0; var oldposn = 1; var loadednum = 0; var i = 0;// general purpose var tempint = 0;// general purpose var Llabel = new String("");// set by parse() var labelNames = new Array(); // set/checked by parse() holds label names var labelNum = new Array(); // holds line num of label. var parts = new Array();// set by parse() var exprnext = 0;// set by isexpr() to next part after expr. var VarValue = 0;// returned by isConstant,isVariable var VarAddress = -1;// returned by isVariable , index into regb var VarWidth = 0;// returned by isVariable var mathOp = new String("");// returned by isMathOp var relOp = new String("");// returned by isRelOp var exprConstant = false;// set if constants found in expr var exprVariableCount;// count of variables in expr var flashAddr = 0;// address in flash memory var flashMemory = new Array(); flashMemory[0] = 25; flashMemory[1] = 48; flashMemory[2] = 62; var flashwidth = 0;// width in flash memory var pauseval = 0; var regb = new Array();// B0 - B27 // byte pinsout; // to be B28 // byte pinsin; // to be B29 // byte dirsb b30 // byte dirsc b31 var atthen; for (ii = 0; ii<31; ii++) { regb[ii] = 0; } // ========================================= function tidyline(line,line_num) { if (line != "") { // debug("tidyline:line " + line_num + " = " + line); } errorpc = line_num; line = line.toLowerCase(); line = line.replace(/\t/g," "); line = line.replace(/^(.*?)\|/,""); // remove line numbers // remove comments line = line.replace(/\'.*/,""); line = line.replace(/;.*/,""); line = line.replace(/\s*rem .*/,""); line = line.replace(/^rem.*/,""); // put spaces around relational operators line = line.replace(/<>/g, " _ne_ "); line = line.replace(/>=/g, " _ge_ "); line = line.replace(/<=/g, " _le_ "); line = line.replace(/>/g, " > "); line = line.replace(/ 0)&&(labelNum[Llabel] !=line_num)) { progerr("662:Duplicate label - '" + Llabel +"' previous at line " + (labelNum[Llabel]+1)); } labelNames.push(Llabel); labelNum[Llabel] = line_num; // add to list of current labels. } //inside tidyline() if ( parts[0]== "do") { if (DO_level > 19) { progerr("557:do nesting level too great"); } DO_level++; debug('tidyline: DO_level++;'); DO_line[DO_level] = line_num; debug("tidyline: do detected line" + line_num + ". Level = " + DO_level); } if ( parts[0]== "exit") { debug('tidyline: exit DO_level=' + DO_level); loopgoto[line_num] = DO_line[DO_level]; debug("tidyline: exit line" + line_num + ". Level = " + DO_level +" do was at line " + DO_line[DO_level]); } //inside tidyline() if ( parts[0]=="loop") { debug('loop at line ' + line_num); if (DO_level < 1) { progerr("569:loop without do"); } else { // set up jump from do loopgoto[DO_line[DO_level]]=line_num + 1; // debug("do at line " + DO_line[DO_level] + "jumps to line " + line_num + "+1"); // set up jump to do loopgoto[line_num] = DO_line[DO_level]; // debug("loop at line " + line_num + " jumps to line " + DO_line[DO_level]); DO_level--; debug('tidyline: DO_level--;' + line_num); } } //inside tidyline() if ( parts[0]=="select") { debug('select at line ' + line_num); SelUplevel(); SelTypeIf = false; SelState = 1;// between select and case return line; } //inside tidyline() if ( (parts[0]=="if") && (parts[parts.length - 1]=="then") ) { debug('if then at line ' + line_num); SelUplevel(); SelTypeIf = true; SelState = 2;// between if and else SelLastCase=line_num; return line; } //inside tidyline() if ( parts[0]=="endselect") { debug("endselect at line " + line_num); if ( (SelState == 2) || (SelState == 3)) {//inside case or else optgoto[SelLastCase] = line_num; //debug("case at line "+SelLastCase +" jumps to "+ line_num); } debug("select state = 0 "+ line_num); if (SelTypeIf) { progerr('609:endselect not expected inside if then else'); return line; } if (Select_level == 0) { progerr('614:endselect without select'); return line; } SelDownlevel(); }//inside tidyline() if ( parts[0]=="endif") { debug("endif at line " + line_num); if ( (SelState == 2) || (SelState == 3)) {//inside case or else optgoto[SelLastCase] = line_num; //debug("case at line "+SelLastCase +" jumps to "+ line_num); } debug("select state = 0 "+ line_num); if (!SelTypeIf) { progerr('627:endif not expected inside select' + Select_level); return line; } if (Select_level == 0) { progerr('631:endif without if then else '); return line; } SelDownlevel(); } //inside tidyline() if ( parts[0]=="case") { debug("case at line " + line_num); if (SelState == 2) { optgoto[SelLastCase] = line_num; //debug("case at line "+SelLastCase +" jumps to "+ line_num); } SelState = 2;// inside a case SelLastCase=line_num; if (SelTypeIf) { progerr('646:case not expected inside if then else'); return line; } } //inside tidyline() if ( parts[0]=="else") { debug("else at line " + line_num); if (SelState == 2) { optgoto[SelLastCase] = line_num; //debug("case at line "+SelLastCase +" jumps to "+ line_num); } else { progerr("657:Unexpected else"); } SelLastCase = line_num; SelState = 3;// inside else } //inside tidyline() if (!(parts[0]=="") && SelState == 1) { progerr("665:Program between select and the first case"); } // ====================================== end new 17 /10/19 return line; } // end of tidyline function SelUplevel() { SelStateArr[Select_level] = SelState; SelLastCaseArr[Select_level] = SelLastCase; SelValueArr[Select_level] = SelValue; SelAddressArr[Select_level] = SelAddress; SelWidthArr[Select_level] = SelWidth; SelTypeIfArr[Select_level] = SelTypeIf; Select_level++; debug("SelUplevel -> " + Select_level); } function SelDownlevel() { Select_level--; debug("SelDownlevel -> " + Select_level); SelState = SelStateArr[Select_level]; SelLastCase = SelLastCaseArr[Select_level]; SelValue = SelValueArr[Select_level]; SelAddress = SelAddressArr[Select_level]; SelWidth = SelWidthArr[Select_level]; SelTypeIf = SelTypeIfArr[Select_level]; } //==================================================================== // sets up parts[0].... // make tabs = spaces!! function parse(line ) { var i=0; Llabel = "";// used for goto search if (line == null) { parts = "".split(" "); return; } parts = line.split(" "); //trace("Parse:" + line + " length=" + parts.length); if (parts[1]==":") { Llabel = parts[0]; //debug("label \"" + Llabel + "\" found"); parts.shift();// remove 1st 2 entries parts.shift(); } //trace("Parts=" + parts.join(",")); } // parse() // ========================================= function cleardata(){ subr_depth = 0; subr_stack = new Array(); // return values executed = new Array(); // whether line was executed symbolsAddr = new Array(); // address of symbol symbolsWidth = new Array(); symbolsValue = new Array(); symbolNames = new Array(); tidyprog = new Array(); regsarraytxt = new Array(); milliseconds =0; DO_level = 0; // bug 0009? } // ========================================= function text2prog() { cleardata(); labelNames = new Array(); // set/checked by parse() holds label names labelNum = new Array(); // holds line num of label. var local_parts; // = new Array() var selstart =0; //uint local_parts = progtext.split('\n'); // 0a maxpc = local_parts.length -1 ; //debug('prog length=' + maxpc); for (pc =0; pc<=maxpc; pc++) { tidyprog[pc]= tidyline(local_parts[pc],pc); } tidyprog[pc] = "stop"; return; } var safety = 100; //======================================================= function run_program( progtextDOM) { for (ii = 0; ii<29; ii++) { regb[ii] = 0; } // showPortC("00000000") if (document.getElementById('runButton').value=="Stop" ) { running = false; document.getElementById('runButton').value="Run" ; return } safety = 100; // alert(" No inrepreter - yet "); progtext = progtextDOM.value; // fetch program from textarea /* fill up tidyprog array: */ text2prog(); milliseconds = 0; fordepth = 0; subr_depth = 0; //start at line 0 pc = 0; line = tidyprog[pc]; document.getElementById('txdispline').innerHTML = line; debug("run:\""+line+"\""); progcount=pc; running = true; safety = 100; document.getElementById('runButton').value="Stop" } //====================== single-step program================================= function step_program( progtextDOM,linenumtxtDOM) { progtext = progtextDOM.value; // fetch program from textarea /* fill up tidyprog array: */ text2prog(); pc = parseInt(linenumtxtDOM.value)-1; line = tidyprog[pc]; document.getElementById('txdispline').innerHTML = line; //debug("Single step:\""+line+"\""); progcount=pc; loadstep(pc); pc=progcount+1; debug("next lineNo=" + pc); linenumtxtDOM.value = "" + pc; document.getElementById('txdispline').innerHTML= document.getElementById("progcontents").value.split('\n')[pc-1]; setpointer(pc); } //======================================================= function look_program( progtextDOM,linenumtxtDOM,step) { progtext = progtextDOM.value; // fetch program from textarea /* fill up tidyprog array: */ text2prog(); if (linenumtxtDOM.value=="") { linenumtxtDOM.value ="0"; } pc = parseInt(linenumtxtDOM.value); debug("PC1="+pc); if (typeof pc == 'undefined') { debug("PC2= Undef"); pc= 0; } pc = pc +step; debug(" V1a"); debug("step="+step); debug("PC3="+pc); if (pc <1){ pc= 1;} if (pc >maxpc){ pc= maxpc;} //debug("PC3a="+pc); line = tidyprog[pc-1]; document.getElementById('txdispline').innerHTML = line; //pc=pc+1; linenumtxtDOM.value = "" + pc; setpointer(pc) } //======================================================== function setpointer(num) { var i; var pointstg = ""; for (i = 0; i<(num-1); i++) { pointstg +="\n"; } //alert("x"+pointstg+"x"); document.getElementById('progpointer').value = pointstg + "->"; } //================================================================ function stopprog() { running = false; document.getElementById('runButton').value="Run" ; } //======================================================== var strt = 0; // part number in line //=============================================================================== function loadstep(posn) { loadednum = posn; //debug('loadstep1 ' +posn); if (posn == -1) { debug('loadstep1a ' +posn); stopprog(); return; } //debug('loadstep(' + posn + '): ' + stepflag + ' ' + stepcount + ' ' + time ); var linenum = posn +1; if (time == timestamps[posn]) { // wait fot 10 ms. milliseconds += 100/FastForward; time += 100;/* for endless loop detection */ return; } timestamps[posn] = time; line = tidyprog[posn]; // program.setSelection(selstartarr[posn],selstartarr[posn+1]); if (line === null) { stopprog(); return; } debug('loadstep(' + posn + '):' + line); parse(line); var Llength = parts.length; //debug('parts = \'' + parts.join('|') + '\' length = '+ Llength); if ((line == '') || (Llength== 0 ) ||(parts[0]=='' && Llength<2 ) ) { progcount++; return; } strt = 0;// position in line //==========================GOSUB====================================== if (Llength >=2 && parts[strt] == 'gosub') { destlabel = parts[1]; debug('Gosub found :' +destlabel); subr_depth++; subr_stack[subr_depth] = posn + 1; progcount = findlabel(destlabel); if (progcount == -1) { progerr('GOSUB can\'t find label (' + destlabel); } return; } //==========================FOR variable = term to term ====================================== if (Llength >= 6 && parts[0] == 'for' && parts[2] == '=' && parts[4] == 'to') { fordepth++; debug('520 fordepth=' + fordepth); if (!isTerm(3)) { progerr('1340:Bad initial value in for statement\n ' + parts[3]); return; } var forinitial = VarValue; if (!isVariable(1) ) { // alert('for loop found :' +parts[1]); progerr('1264:Bad storage in for statement\n ' + parts[1]); return; } forreg[fordepth] = VarAddress;// register forwidth[fordepth] = VarWidth; debug('For VarAddress=' + VarAddress); debug('For VarWidth=' + VarWidth); // xyzzy needs revamping to accept variable of width 8 or 16 // FIX start value only (parts[3]) should be Term (const / variable / symbol) if ((VarWidth != 16) && (forinitial > 255) ) { progerr('1355:FOR initial value (' + parts[3] + ') is too large for byte for variable ' + parts[1] ); return; } regb[VarAddress] = forinitial & 255; if (VarWidth == 16) { regb[VarAddress+1] = parseInt(String(forinitial/256)); } if (forreg[fordepth] <7) { regsarraytxt[forreg[fordepth]] = String(regb[forreg[fordepth]]); } if (forreg[fordepth] <6) { regsarraytxt[forreg[fordepth]+1] = String(regb[forreg[fordepth]+1]); } dispForVars(); showWords(); debug('regb[' + forreg[fordepth] + '] set to ' + regb[forreg[fordepth]]); // deal with variable/constant as if (!isTerm(5)) { progerr('1281:Variable or constant expected ' + parts[0] + parts[1] +parts[2] +parts[3] +parts[4]); return; } if ((forwidth[fordepth] != 16) && (VarValue > 255) ) { progerr('1377:FOR final value (' +parts[5] + ') is too large for byte for variable ' + parts[1] ); return; } forlimit[fordepth] = VarValue; debug('Limit = ' + forlimit[fordepth]); for_stack[fordepth] = posn + 1;// place where next jumps to progcount++; return; } //==========================NEXT====================================== if (parts[0] == 'next') { debug('next found :' + line + ' forreg[fordepth] = ' + forreg[fordepth]); // needs to cope with vaiable width 8 or 16. // use isvariable() check Varaddress varwidth against stored values. if (!isVariable(1) ) { progerr('1380:NEXT - variable expected\n ' + parts[1]); return; } if ( (VarAddress != forreg[fordepth]) || (VarWidth != forwidth[fordepth] ) ) { progerr('1300:next - register ' + parts[1] + ' isn\'t same as in the FOR statement'); return; } forvalue = regb[forreg[fordepth]]; if (forwidth[fordepth] == 16) { forvalue += regb[forreg[fordepth]+1] *256 ; } // see if time to exit if (forvalue == (forlimit[fordepth])) { fordepth--; // alert('fordepth=' + fordepth); dispForVars(); progcount++; return; } if (forlimit[fordepth] > forvalue) { regb[forreg[fordepth]] = (regb[forreg[fordepth]] + 1) & 255; if ((regb[forreg[fordepth]] == 0) && (forwidth[fordepth] == 16)) { regb[forreg[fordepth]+1] = (regb[forreg[fordepth]+1] + 1) & 255; } } else { regb[forreg[fordepth]] = (regb[forreg[fordepth]] - 1) & 255; if ((regb[forreg[fordepth]] == 255) && (forwidth[fordepth] == 16)) { regb[forreg[fordepth]+1] = (regb[forreg[fordepth]+1] - 1) & 255; } } regsarraytxt[forreg[fordepth]] = String(regb[forreg[fordepth]]); regsarraytxt[forreg[fordepth]+1] = String(regb[forreg[fordepth]+1]); showWords(); dispForVars(); // loop progcount = for_stack[fordepth]; return; } //============================== BRANCH =========================== /* b0=2 branch b0,(L1,L2,L3,L4,L5) L0: L1: L2: L3: L4: L5: L6: L7: */ //branch b1,(btn0,btn1, btn2, btn3, btn4) var ix = 0; if (Llength >=3 && parts[0] == 'branch') { if (! isVariable(1) ) { debug("branch: variable expected " + parts[1]); progerr("1526:bad variablein branch"); return; } ix = 3 + VarValue *2 debug('branch: "' + parts[1] + '" "' + parts[2]+ '" "' + parts[3]+ '" "' + parts[4] + '"'); if (Llength >= ix) { destlabel = parts[ix].replace(/\(|\)/,""); debug('branch to label ' +destlabel); progcount = findlabel(destlabel); if (progcount == -1) { progerr('689:branch can\'t find label "' + destlabel +'"'); } } else { debug('branch: variable too large ' + VarValue); progcount++; } return; } //==========================SOUND====================================== if (Llength >=2 && parts[0] == 'sound') { var rawline = program.text.split('\r')[progcount]; rawline = rawline.replace(/^(.*?)\|/,""); // remove line numbers rawline = rawline.replace(/\t/g," "); // remove tabs rawline = rawline.replace(/ *\'.*$/,""); // remove comments debug('Sound found: ' + rawline); progcount++; return; } //==========================GOTO====================================== if (Llength >=2 && parts[0] == 'goto') { destlabel = parts[1]; debug('Goto found: ' +destlabel); progcount = findlabel(destlabel); if (progcount == -1) { progerr('720:GOTO can\'t find label (' + destlabel+')'); } return; } //============================LET======================= if ( (parts[strt] == "let") || ( (parts.length >= 3) && (parts[1]== "=")) ) { if ( parts[strt] == "let") { strt = 1; } if ( (parts.length >= (strt + 3)) && (parts[strt+1] == "=")&& (isExpr(strt+2)) ) { debug("exec: LET " + parts[strt] + parts[strt+1] + parts[strt+2]); var rhs = VarValue;// from isExpr debug('rhs=' + rhs); //deal with LHS debug('deal with LHS' + strt + ' ' + parts[strt]); if (isVariable(strt) ) { debug('VarWidth=' + VarWidth); debug('VarAddress=' + VarAddress); if (VarWidth >=8) { regb[VarAddress] = (rhs & 255); showWords(); if (VarWidth == 16) { regb[VarAddress+1] = ( (rhs>>8) & 255); regsarraytxt[VarAddress+1] = String(regb[VarAddress+1]); showWords(); } } else { regb[VarAddress] |= 1<< VarWidth; regb[VarAddress] ^= 1<< VarWidth; regb[VarAddress] |= (rhs&1)<< VarWidth; } if (VarAddress == 28) { setmotors(regb[28]); } regsarraytxt[VarAddress] = String(regb[VarAddress]); showWords(); } else { debug("exec: LET bad LHS " + parts[strt]); progerr("1376:bad left hand side of let"); return; } progcount++; return; } else { progerr("1382:Bad Let expression " + line); } } //============================SYMBOL======================= if (parts[strt] == "symbol") { trace ("exec: SYMBOL " + parts[0] + ","+ parts[1] + ","+ parts[2] + ","+ parts[3] ); trace ('executed['+ progcount + ']=' + executed[progcount]); if (executed[progcount] == true) { progcount++; return; } if (parts.length < 3) { debug(parts[strt] + " " +parts[strt+1]); progerr("Symbol command too short"); return true; } if (parts[2]!= "=") { progerr("Symbol command needs \"=\" "); return true; } var newSymbolName; if (isSymbol(1)) { progerr("Symbol already defined :" + line); return true; } executed[progcount] = true; if (isVariable(1) ){ progerr("Symbol name cannot be variable name :" + line); return true; } newSymbolName = parts[1]; if (!isExpr(3)) { progerr("1430:Bad symbol value " + line); return; } if (exprVariableCount==0) { VarAddress = -1; VarWidth = 16; } if (VarAddress == -1) { trace ("Constant symbol " + newSymbolName + " = " + VarValue); } else { trace ("Variable symbol " + newSymbolName + " A= " + VarAddress + ", W=" + VarWidth); if (VarWidth == 8) { symbols[VarAddress].text += ' ' + newSymbolName; //Variables.reDraw(); } } symbolsAddr[newSymbolName] = VarAddress; symbolsValue[newSymbolName] = VarValue; symbolsWidth[newSymbolName] = VarWidth; symbolNames.push(newSymbolName); progcount++; return; } //==========================PAUSE====================================== if (parts[0] == 'pause') { if (Llength < 2) { errorpc = posn; progerr('1391:Pause value needed'); return; } if ( !isTerm(1) ) { debug("exec: pause value expected "); progerr("1397:pause: value expected (" + parts[1] + ")"); progcount++; return; } milliseconds = milliseconds + (VarValue/FastForward); time += VarValue;/* for endless loop detection */ progcount++; return; } //==========================RETURN====================================== if (parts[0] == 'return') { debug('return, depth= ' + subr_depth); if (subr_depth == 0) { errorpc = posn; progerr('1413:Return without gosub.\nDo you need a stop at the end of main program?'); return; } progcount = subr_stack[subr_depth--]; // alert('Return to ' + progcount ); return; } // ====DO=====/======LOOP=============================== // uses loopgoto[progcount] to point to statement to jump to debug(parts[0]); if ( parts[0]=="do" || parts[0]=="loop") { //debug("exec: DO/LOOP "); var oldprogcount = progcount; // loop forever if (( parts.length == 1) || parts[1]=="" ) { // look for length = 2 && last part == "") // debug("exec: simple DO/LOOP"); if ( parts[0]=="do" ) { DO_level++; debug('DO_level='+DO_level); DO_exit[DO_level] = loopgoto[progcount]; progcount++; } else { if ( loopgoto[progcount] >=0 ) { progcount = loopgoto[progcount]; DO_level--; debug('DO_level='+DO_level); } else { progerr("1436:LOOP without DO " + loopgoto[progcount]); progcount++; } } return; } // conditional do loop strt = 1; if ( !(parts[strt]=="until") && !(parts[strt]=="while") ) { progerr("1446:DO - while/until expected"); progcount++; return; } // debug("exec: DO/LOOP " + parts[1] ); if ( parts[0]=="do" ) { DO_level++; debug('DO_level='+DO_level); } strt++; while (true) { if ( !isVariable(strt) ) { debug("exec: DO variable expected ("+ parts[strt] + ")" ); progerr("1458:DO - variable expected (" + parts[strt] + ")" ); progcount++; return; } lhsVar = VarValue; lhsWidth = VarWidth; strt++; if ( !isRelOp(strt) ) { debug("exec: DO relop expected " ); progerr("1468:DO - relation expected (" + parts[strt] + ")"); progcount++; return; } strt++; if ( !isTerm(strt) ) { debug("exec: DO value expected "); progerr("1476:DO - value expected (" + parts[strt] + ")"); progcount++; return; } // evaluate truth so far... // debug("do: comparing: " + lhsVar + " " + relOp + " " + VarValue); truth=false; if (lhsWidth ==8) { lhsVar &= 255; VarValue &= 255; } if ( relOp=="=") { truth = (lhsVar == VarValue); } else if ( relOp=="_ge_") { truth = (lhsVar >= VarValue); } else if ( relOp=="_le_") { truth = (lhsVar <= VarValue); } else if ( relOp=="is") { truth = (lhsVar == VarValue); } else if ( relOp=="_ne_") { truth = (lhsVar != VarValue); } else if ( relOp==">") { truth = (lhsVar > VarValue); } else if ( relOp=="<") { truth = (lhsVar < VarValue); } else { debug("do: bad relOp " + relOp ); } strt++;// points to just after condition //debug("DO, strt = " + strt); //debug("DO, parts.length = " + parts.length); // parts[strt] should be OR or AND..... if (( parts.length == (strt ) ) || parts[strt]=="") { // debug("DO end of condition " + parts[1]); break; } if ( parts[strt]=="and" ) { if (!truth ) { // debug("DO: AND when false " + parts[1]); break; } else { // debug("DO: AND when true " + parts[1]); strt++;// points to just after and continue; } } if ( parts[strt]=="or" ) { if (truth ) { // debug("DO: OR when true " + parts[1]); break; } else { // debug("DO: OR when false " + parts[1]); strt++;// points to just after OR continue; } } debug("exec: DO. or/and expected (" + parts[strt] + ")"); progerr("1538:BAD DO command"); progcount++; return; }// while() if ( parts[0]=="do" ) { truth = !truth; } if ( parts[1]=="while") { truth = !truth; } if (truth) { progcount++; } else { if ( loopgoto[progcount] >=0 ) { progcount = loopgoto[progcount]; if ( parts[0]=="do" ) { DO_level--; debug('DO_level='+DO_level); } } else { progerr("1555:DO/LOOP without LOOP/DO"); progcount++; if ( parts[0]=="loop" ) { DO_level--; debug('DO_level='+DO_level); } } } return; }// do //IF ============================IF==================================== if ( parts[0] == "if" ) { // debug("exec: IF"); oldprogcount = progcount; strt = 1; atthen = false; while (true) { if (!atthen) { if ( !isVariable(strt) ) { debug("exec: IF variable expected"); progerr("1573:IF - variable expected (" + parts[strt] + ")"); progcount++; return; } lhsVar = VarValue; lhsWidth = VarWidth; debug("if " + parts[strt] +" ok 994"); strt++; if ( !isRelOp(strt) ) { debug("exec: IF relop expected"); progerr("1583:IF - relation expected (" + parts[strt] + ")"); progcount++; return; } debug("if " + parts[strt] + " relop ok 1004"); strt++; if ( !isTerm(strt) ) { debug("exec: IF value expected"); progerr("1591:IF: value expected (" + parts[strt] + ")"); progcount++; return; } // evaluate truth so far... // debug("if: comparing: " + lhsVar + " " + relOp + " " + VarValue); truth=false; if (lhsWidth ==8) { lhsVar &= 255; VarValue &= 255; } if ( relOp == "=") { truth = (lhsVar == VarValue); } else if ( relOp == "_ge_") { truth = (lhsVar >= VarValue); } else if ( relOp == "_le_") { truth = (lhsVar <= VarValue); } else if ( relOp == "is") { truth = (lhsVar == VarValue); } else if ( relOp == "_ne_") { truth = (lhsVar != VarValue); } else if ( relOp == ">") { truth = (lhsVar > VarValue); } else if ( relOp == "<") { truth = (lhsVar < VarValue); } else { debug("if: bad relOp " + relOp ); } debug("truth =" + truth); strt++;// points to then // parts[strt] should be then , or or and..... if ( !(parts.length >= (strt + 1) )) { debug("exec: IF. then/or/and expected"); progerr("1628:IF - then/or/and expected (" + parts[strt] + ")"); progcount++; return; } } // ==========================THEN========================= if ( parts[strt] == "then" ) { debug("if.. then"); if ( !(parts.length >= (strt + 2) )) { debug("exec: IF... then.. else.. endif"); SelUplevel(); SelTypeIf = true; if (!truth) { SelState = 2;// case not detected debug("exec: IF... then jumps to else/endif"); progcount = optgoto[progcount]; return; } debug("exec: IF... then falls into then clause"); progcount++; SelState = 3;// case detected: so that eventual else will jump to endif return; } if (truth) { if ( (progcount = findlabel(parts[strt+1])) == -1) { /* insert if then else endif code here */ debug("exec: IF. LABEL not found"); progerr('IF THEN can\'t find label (' + parts[strt+1]); progcount=oldprogcount+1; return; } return;// take jump } //go to next command / goto progcount=oldprogcount+1; return; } else if ( parts[strt] == "and" ) { if (!truth) { //go to next command debug("exec: IF. AND when false"); // scan forwards till then while (!(parts[strt] == "then")) { if (!(parts.length >= (strt + 1) )) { /* insert if then else endif code here */ debug("exec: IF. then not found"); progerr("1681:IF - \"then\" expected"); } //trace('strt=' + strt + ' parts[strt]=' + parts[strt] ); strt++;// scan forwards //trace('step, strt=' + strt + ' parts[strt]=' + parts[strt] ); } atthen = true; continue;//process the then with truth = false } strt = strt+1;// step over the and debug("exec: IF. AND when true"); continue;// process the variable after the and } else if ( parts[strt] == "or" ) { if (truth) { //trace('strt=' + strt + ' parts[strt]=' + parts[strt] ); // scan forwards till then while (!(parts[strt] == "then")) { if (!(parts.length >= (strt + 1) )) { /* insert if then else endif code here */ debug("exec: IF. then not found"); progerr("1681:IF - \"then\" expected"); } //trace('strt=' + strt + ' parts[strt]=' + parts[strt] ); strt++;// scan forwards //trace('step, strt=' + strt + ' parts[strt]=' + parts[strt] ); }// while atthen = true; continue;// process the then with truth = true } strt = strt+1;// skip the or // debug("exec: IF. OR when false"); continue;// process the variable after the or } else { // debug("exec: IF. then/or/and expected"); progerr("1702:BAD IF command then/or/and expected"); progcount++; return; } }// while() }// if // endif ========================ENDIF================================= if ( parts[0]=="endif") { debug("endif at line " + progcount); debug("select state = 0 " + progcount); SelDownlevel(); progcount++; return; } // SELECT ============================SELECT==================================== if ( parts[0] == "select") { debug("select at line " + progcount + ". len=" + parts.length); strt = 1; if (isString("case" , strt)) { strt++;} // skip over optional case //if ((parts.length < 3) || (!(parts[1] == "case"))) { //progerr("1715:Bad select statement"); //return; //} SelUplevel();// save state of outer selects / if SelTypeIf = false; SelState = 1;// between select and case //strt++; // step on to variable if ( !isVariable(strt)) { progerr("1725:select - variable expected (" + parts[strt] + ")"); progcount++; return; } SelAddress = VarAddress; SelWidth = VarWidth; SelValue = VarValue; //debug("addr:" + SelAddress + " width:" + SelWidth + " value:" + SelValue ); SelState = 1;// between select and case progcount++; return; } // EndSELECT ========================ENDSELECT================================= if ( parts[0] == "endselect") { if (Select_level == 0) { progerr("1741:endselect without select"); } SelDownlevel(); progcount++; return; } // case =============================CASE=================================== if ( parts[0] == "case") { if (SelState == 3) { progcount = optgoto[progcount]; } else { strt=2; if (parts.length < strt) { progerr("1764:case - value(s) needed after case"); return; } // term to term if ( isTerm(strt-1) && isString("to" , strt)) { if (SelValue < VarValue) { progcount = optgoto[progcount]; return; } if (!isTerm(strt+1)) { progerr("1774:case - value needed after to"); return; } if (SelValue > VarValue) { progcount = optgoto[progcount]; return; } debug("case: const to const condition met"); progcount++; SelState = 3; return; } // case const while ( (parts.length >= strt) && ( isTerm(strt-1) )) { if (SelValue == VarValue) { debug("case: simple condition met"); progcount++; SelState = 3; return; } if (parts.length == strt) { // simple case progcount = optgoto[progcount]; return; } if ( !(parts[strt] == ",")) { progerr("1800:case - comma expected (" + parts[strt] + ")"); return; } strt+=2; } progcount++; } return; } // else ============================ELSE==================================== if ( parts[0] == "else") { if (SelState == 3) {//inside else progcount = optgoto[progcount]; return; } SelState = 3; progcount++; return; } //INC/DEC ================================================================ if ( ( parts[0]== "inc" ) || ( parts[0] == "dec" )) { strt=1; if (!isVariable(strt) ) { debug("exec: INC/DEC bad variable "); progerr("1831:Need variable after INC or DEC"); return; } if ( parts[0]== "inc" ) { rhs = VarValue + 1; } else { rhs = VarValue - 1; } if (VarWidth >=8) { regb[VarAddress] = rhs & 255; regsarraytxt[VarAddress] = String(regb[VarAddress]); if (VarWidth == 16) { regb[VarAddress+1] = ( (rhs>>8) & 255); regsarraytxt[VarAddress+1] = String(regb[VarAddress+1]); } showWords(); } else { regb[VarAddress] |= 1<< VarWidth; regb[VarAddress] ^= 1<< VarWidth; regb[VarAddress] |= (rhs&1)<< VarWidth; } progcount++; return; } var loopflag; // =============================HIGH============================ if (parts[0] == "high") { progcount++; debug("High at line "+progcount); strt=1; loopflag = true; while (loopflag) { //debug("ghh "+parts[strt]); if (parts[strt].slice(0,2) == "b."){ parts[strt] = parts[strt].slice(2); } if (!isConstant(strt)) { debug("high: - bad arg"); progerr("2200:high: - bad arg"); } i=VarValue; if ( ( i < 0) || ( i > 7)) { debug("exec: HIGH - bad arg"); progerr("1869:high - bad pin number"); return; } regb[28] |= 1 << i; if (isString("," , strt+1)) { strt = strt+2; } else { loopflag = false; } } setmotors(regb[28]); setLEDs(regb[28]); debug("exec: PINS = " + regb[28]); return; } // =============================LOW============================ if (parts[0] == "low") { progcount++; strt=1; loopflag = true; while (loopflag) { if (!isConstant(strt)) { debug("exec: LOW - bad arg"); progerr("2227:low - bad arg"); } i=VarValue; if ( ( i < 0) || ( i > 7)) { debug("exec: LOW - bad arg"); progerr("1890:low - bad pin number"); return; } regb[28] |= 1 << i; regb[28] ^= 1 << i; if (isString("," , strt+1)) { strt = strt+2; } else { loopflag = false; } } setmotors(regb[28]); setLEDs(regb[28]); debug("exec: PINS = " + regb[28]); return; } // =============================TOGGLE============================ if (parts[0] == "toggle") { progcount++; // debug("exec: TOGGLE"); if (!isConstant(1)) { debug("exec: TOGGLE - bad arg"); progerr("1905:toggle - bad argument"); } i=VarValue; if ( ( i < 0) || ( i > 7)) { debug("exec: TOGGLE - bad arg"); progerr("1910:toggle - bad pin number"); return; } regb[28] ^= 1 << i; debug("exec: PINS = " + regb[28]); setmotors(regb[28]); return; } //==========================STOP====================================== if (parts[0] == 'stop') { debug('Decode:stop'); stopprog(); return; } if (line == '') { progcount++; return; } errorpc = progcount; stopprog(); progerr('1165:Unknown command\n ' + line); } // end of instruction decode //================================================================ function isConstant( partNo ) { var cons = ""; var radix =0; if (isSymbol(partNo) && (VarAddress <0)) { return true; } // java.util.regex.Pattern // boolean b = Pattern.matches("a*b", "aaaaab"); //Character classes //[abc] a, b, or c (simple class) //[^abc] Any character except a, b, or c (negation) //[a-zA-Z] a through z or A through Z, inclusive (range) //[a-d[m-p]] a through d, or m through p: [a-dm-p] (union) //[a-z&&[def]] d, e, or f (intersection) //[a-z&&[^bc]] a through z, except for b and c: [ad-z] (subtraction) //[a-z&&[^m-p]] a through z, and not m through p: [a-lq-z](subtraction) // //Predefined character classes //. Any character (may or may not match line terminators) //\d A digit: [0-9] //\D A non-digit: [^0-9] //\s A whitespace character: [ \t\n\x0B\f\r] //\S A non-whitespace character: [^\s] //\w A word character: [a-zA-Z_0-9] //\W A non-word character: [^\w] if (partNo >= parts.length) { return false; } cons = new String(parts[partNo]); debug("isConstant(" +cons + ")"); VarValue=0; pattern=/^\d+$/; if (cons.charAt(0) == "$") { radix=16; cons=cons.substring(1); } else if (cons.charAt(0) =="%") { radix=2; cons=cons.substring(1); } else if (pattern.test(cons)) {// 1 or more digits radix=10; } else { debug('not constant' + pattern + ' ' + cons); return false; } VarValue = parseInt(cons, radix) ; if (VarValue >65535) { progerr("191:Constant too large"); } // assume 16 bit numbers VarWidth=16; return true; } // ================================================================ function isSymbol( partNo) { var ValueAddress; var Address = 0; var Value = 0; var Width = 0; debug("isSymbol " + parts[partNo]); if (partNo >= parts.length) { debug("isSymbol return false partNo"); return false; } if ( symbolsAddr[parts[partNo]] == null) { debug("isSymbol return false -symbolsAddr "); return false; } Address = symbolsAddr[parts[partNo]]; Value = symbolsValue[parts[partNo]]; Width = symbolsWidth[parts[partNo]]; // bug - does not give regb[29] (input) for varvalue of pins VarAddress = Address; if (VarAddress == 28) { ValueAddress = 29; } else { ValueAddress = VarAddress; } VarWidth = Width; if (VarAddress >=0) { if (VarWidth >=8) { VarValue = regb[ValueAddress]; if (VarWidth == 16) { VarValue += 256*regb[ValueAddress+1]; } } else { VarValue = (regb[ValueAddress] >> VarWidth) & 1; } } else { VarValue = Value; } debug("isSymbol true: " + parts[partNo] + " A=" + VarAddress + " V=" + VarValue + " W=" + VarWidth ); return true; } //=================================================================== function isString(strg , partNum) { if (strg == parts[partNum] ) { return true; } return false; } //================================================================ function findlabel(lookfor) { var myLabel = new String(); var myline = new String(); /*debug('findlabel('+lookfor+')'+runflag);*/ var lines = new Array(); lines = progtext.split('\n'); var linno = 0 for (var lline in lines) { myline = lines[lline]; myline = myline.replace(/^(.*?)\|/,""); // remove line numbers myline = myline.toLocaleLowerCase(); //debug(String(lline) + ':' + myline); myline = myline.replace(/\'(.*)/,""); if (myline.indexOf(':') != -1) { myLabel = myline.substring(0,myline.indexOf(':')); myLabel = myLabel.replace(/\s/g,""); if (myLabel == lookfor) { /*debug('label found '+ linno);*/ return linno; } //debug('label not found |'+ myLabel + '|' + lookfor); } linno= linno+1; } progerr('927:Can\'t find label:' + lookfor); return -1; } //====================================== //================================================================ // returns expression value in VarValue function isExpr( partNo ) { debug("isExpr(" + parts[partNo] + ")"); var tempVal = 0; var neg = 1; exprVariableCount=0; if ( partNo >= parts.length) { return false; } if ( parts[partNo] == "-") { neg = -1; partNo++; } if ( !isTerm(partNo)) { return false; } // check for pin 3,4,5 varaddr is 28 for pins if ((VarAddress==28) && (VarWidth >=3 && VarWidth<=5)) { progerr("211:Bad bit - " + parts[partNo]); } VarValue *= neg; while (isMathOp(partNo+1)) { tempVal = VarValue; // term + if ( !isTerm(partNo+2)) { //alert("isExpr: bad term (" // + (int)(partNo+2) +")"); progerr("223:Variable or constant expected"); return false; } // check for pin 3,4,5 varaddr is 28 for pins if ((VarAddress==28) && (VarWidth >=3 && VarWidth<=5)) { progerr("228:Bad bit - " + parts[partNo+2]); } // term + term // do maths into VarValue partNo += 2; if (mathOp == "&") { VarValue = tempVal & VarValue; } else if (mathOp == "|") { VarValue = tempVal | VarValue; } else if (mathOp == "^") { VarValue = tempVal ^ VarValue; } else if (mathOp == "+") { VarValue = tempVal + VarValue; } else if (mathOp == "-") { VarValue = tempVal - VarValue; } else if (mathOp == "*") { VarValue = tempVal * VarValue; } else if (mathOp == "/") { if (VarValue == 0) { VarValue = tempVal ; alert("isExpr: divide by zero (" + parts[partNo] +")"); progerr("251:Divide by zero"); } else { VarValue = tempVal / VarValue; } } }// while exprnext = partNo+1; return true; } // ================================================================ function isTerm( partNo ) { if (isConstant(partNo)) { exprConstant = true; return true; } if (isVariable(partNo)) { exprVariableCount++; return true; } return false; } function isRelOp( partNo ) { var nam = new String(); if (partNo >= parts.length) { return false; } nam = parts[partNo]; if ( (nam=="=") || (nam== "_ge_") || (nam=="_le_") || (nam=="is") || (nam=="_ne_") || (nam==">") || (nam=="<") ) { relOp = nam; return true; } return false; } //================================================================ function isMathOp( partNo ) { var nam; if (partNo >= parts.length) { return false; } nam = parts[partNo]; if ( (nam == "&") || (nam == "|") || (nam == "^") || (nam == "+") || (nam == "-") || (nam == "/") || (nam == "*") ) { mathOp = nam; return true; } return false; } //================================================================ function isVariable( partNo ) { var nam; var number; if (isSymbol(partNo) && (VarAddress >=0)) { return true; } if (partNo >= parts.length) { return false; } nam = parts[partNo]; debug('isVariable (' + parts[partNo] + ')'); // pins pinsb if (nam == "pinsb") { VarValue = regb[28];// reads pinsb VarAddress = 28;// writes to pinsout VarWidth = 8; debug('PINSB'); return true; } // pins pinsb if (nam == "dirsb") { VarValue = regb[30];// reads pinsb VarAddress = 30;// writes to pinsout VarWidth = 8; debug('DIRSB'); return true; } // pinsb if (nam == "pinsc") { VarValue = regb[29];// reads pinsin pinsc VarAddress = 29;// writes to pinsc VarWidth = 8; debug('PINSC value='+VarValue); return true; } if (nam == "infra") { VarValue = regb[13];// reads pinsin VarAddress = 13;// writes to pinsout VarWidth = 8; debug('infra'); return true; } // bit0 .. bit15 pattern = /^bit\d+$/; if (pattern.test(nam)) { number = nam.substring(3); VarAddress = parseInt(number, 10); if ( (VarAddress >= 0 ) && (VarAddress <= 7 )) { VarWidth = VarAddress; VarValue = (regb[0]>>VarWidth) & 1; VarAddress = 0; debug('BIT 0-7 '); return true; } else if ( (VarAddress >= 8 ) && (VarAddress <= 15 )) { VarWidth = VarAddress-8; VarValue = (regb[1]>>VarWidth) & 1; VarAddress = 1; debug('BIT 8-15 '); return true; } else { alert("Bad bit:" + nam); } progerr("405:Bad bit - " + nam); return false; }// bit0-7 // pin0 .. pin7 pattern = /^(pin|input|pinc)\d+$/; if (pattern.test(nam)) { if (Remote.y > 0) { if (Remote_line1.text == '') { regb[29] |= 1; } else { regb[29] &= 254; } } number = nam.substring(nam.length-1,nam.length); VarAddress = parseInt(number, 10); if ( (VarAddress >= 0 ) && (VarAddress <= 7 )) { VarWidth = VarAddress; VarValue = (regb[29]>>VarWidth) & 1;// pins input value VarAddress = 28; debug("pin found:" + VarAddress + " " +VarWidth + " " + VarValue); return true; } alert("Bad pin:" + nam); progerr("421:Bad pin - " + nam); return false; }// pin0-7 // b0 .. b13 pattern = /^b\d+$/; if (pattern.test(nam)) { debug('B0 - 27 '); number = nam.substring(1,nam.length); VarAddress = parseInt(number, 10); if ( (VarAddress >= 0 ) && (VarAddress <= 27 )) { VarValue = regb[VarAddress]; VarWidth = 8; return true; } debug("Bad b register:" + nam); progerr("438:Bad b register - " + nam); return false; }// b0-b13 // w0 .. w13 pattern = /^w\d+$/; if (pattern.test(nam)) { number = nam.substring(1,nam.length); VarAddress = parseInt(number, 10); if ( (VarAddress >= 0 ) && (VarAddress <= 13 )) { VarAddress = VarAddress * 2; VarValue = regb[VarAddress] + (256 * regb[VarAddress+1]); VarWidth = 16; return true; } alert("Bad w register:" + nam); progerr("454:Bad w register - " + nam); return false; }// w0-b6 return false; }// isVar() //=================================================================== function binstring(value) { var result = ""; if ((value & 128) == 0 ) {result = "0";} else {result = "1"; } if ((value & 64) == 0 ) {result += "0";} else {result += "1"; } if ((value & 32) == 0 ) {result += "0";} else {result += "1"; } if ((value & 16) == 0 ) {result += "0";} else {result += "1"; } if ((value & 8) == 0 ) {result += "0";} else {result += "1"; } if ((value & 4) == 0 ) {result += "0";} else {result += "1"; } if ((value & 2) == 0 ) {result += "0";} else {result += "1"; } if ((value & 1) == 0 ) {result += "0";} else {result += "1"; } return result; } function progerr(txt) { var fields = txt.split(':'); alert('BASIC Program error line '+ (loadednum+1) + '\ncode:' + fields[0]+'\n'+fields[1]); running = false; document.getElementById('runButton').value="Run" ; //stopprog(); } function checkrw(str) { str = str.toLowerCase(); var chk = "," + str + ","; var rwords = ",backward,branch,do,loop,bcdtoascii,calibfreq,call,count,data,debug,disablebod,disconnect,eeprom,end,endif,endrem,for,forward,gosub,goto,halt,high,hpwm,hpwmout,i2cslave,i2cwrite,i2cread,if,infrain,infrain2,infraout,input,keyin,keyled,let,lookdown,lookup,low,nap,next,output,pause,peek,play,poke,porta,portb,portc,pot,pulsin,pulsout,pwm,pwmout,random,read,readadc,readadc10,readdac,readdac10,readi2c,readmem,readoutputs,readowclk,resetowclk,readowsn,readportc,readpinsc,readtemp,readtemp12,reconnect,reset,return,reverse,run,serin,serout,serrxd,sertxd,servo,servopos,setint,setfreq,slavei2c,sleep,sound,stop,switch,switchoff,switchon,symbol,toggle,touch,touch16,tune,wait,write,writei2c,writemem,porta,portc,to,then,step,on,off,is,picaxe,picaxe08,picaxe08m,picaxe14m,picaxe14m2,picaxe20m,picaxe20m2,picaxe20x2,picaxe18,picaxe18a,picaxe18m,picaxe18m2,picaxe18x,picaxe28,picaxe28a,picaxe28x,picaxe28x1,picaxe28x2,picaxe40x,picaxe40x1,picaxe40x2,error,freq,gosubs,define,undefine,include,ifdef,ifndef,simspeed,sim,simtask,terminal,com,slot,no_table,no_data,no_end,revision,a,b,c,d,include,"; if (rwords.indexOf(chk) != -1) { return true; } //trace ('Label "' + chk+ '" is not a reserved word'); return false; } function mynextstep() { if ( running == true) { //debug("mynext progcntc= "+ progcount); loadstep(progcount); pc=progcount+1; //PC is human-readable line number debug("next lineNo=" + pc); //document.getElementById('DispPC').value = "" + pc; //document.getElementById('txdispline').innerHTML= document.getElementById("progcontents").value.split('\n')[pc-1]; //setpointer(progcount); //safety = safety-1; //if (safety <1) { running = false;} } else { document.getElementById('runButton').value="Run" ; } } function dispForVars(){ }