/*http://esolangs.org/wiki/TwoFiftyFiveUsage:new VM255("program", function(){input}, function(){output}).run();Example usage (Cat program):new VM255("FF02 FFFF FE*FA FA*FE FDFF FF*FC",function(){ var s=prompt("INPUT"); s=(s==null?"":s); var out=new Array(s.length); for(var i=0; i<out.length; i++) out[i]=s.charCodeAt(i); return out;},function(i){ document.body.innerText+=String.fromCharCode(i);}).run();*/class VM255{ //string, function, function constructor(program, input, output) { this.ram=new Uint8Array(256); this.stack=[]; this.prog=[]; //filled in lower //must return an int[] when called this.input=input; this.inputBuffer=[]; //must accept a int and output it this.output=output; //special values this.EOF=0x00; this.IP=0xFF; this.NAND_A=0xFE; this.NAND_B=0xFD; this.NAND_OUT=0xFC; this.STACK_IO=0xFB; this.STD_IO=0xFA; this.RESERVED=[0xF9]; //fill in this.prog let word=""; for(let c of program) { if("0123456789abcdef*".indexOf(c.toLowerCase())!=-1) { word+=c.toLowerCase(); //count the number of hex digits in word let hexCount=0; for(let h of word) if("0123456789abcdef".indexOf(h)!=-1) hexCount++; if(hexCount==4) { //we have a word //spilt it into bytes let a=""; let b=""; if(word[0]=='*') { a=word.slice(0,3); b=word.slice(3, word.length); } else { a=word.slice(0,2); b=word.slice(2, word.length); } //translate them to bytes let aByte; let bByte; if(a[0]=='*') aByte=new VM255Byte(parseInt(a.slice(1,3),16),true); else aByte=new VM255Byte(parseInt(a,16)); if(b[0]=='*') bByte=new VM255Byte(parseInt(b.slice(1,3),16),true); else bByte=new VM255Byte(parseInt(b,16)); //and into a byte pair let pair=new VM255Word(aByte, bByte); //put it in the program array this.prog.push(pair); if(this.prog.length>256) throw "ROM Overflow Error"; //reset the word word=""; } } } if(word.length!=0) throw "Extraneous Nibbles Error"; } //RAM manip getVal(p) { if(this.RESERVED.indexOf(p)!=-1) console.warn("RAM("+p.toString(16).padStart(2, "0")+") is reserved for future extensions."); switch(p) { case this.STACK_IO: if(this.stack.length>0) return this.stack.pop(); else throw "Empty Stack Error"; case this.STD_IO: //if input buffer is empty, refill it if(this.inputBuffer.length==0) { this.inputBuffer=this.input(); this.inputBuffer.push(this.EOF); } return this.inputBuffer.shift(); default: return this.ram[p]; } } setVal(v, p) { if(this.RESERVED.indexOf(p)!=-1) console.warn("RAM("+p.toString(16).padStart(2, "0")+") is reserved for future extensions."); switch(p) { case this.NAND_A: case this.NAND_B: this.ram[p]=v; this.updateNAND(); break; case this.NAND_OUT: throw "Read Only Error: RAM("+p.toString(16).padStart(2, "0")+") is reserved for NAND Output, and is read only."; break;//not needed, but it was bugging me case this.STACK_IO: this.stack.push(v); break; case this.STD_IO: this.output(v); break; default: this.ram[p]=v; } } //IP Manip getIP() { return this.getVal(this.IP); } setIP(p) { this.setVal(p, this.IP); } incIP() { this.setIP(this.getIP()+1); } //NAND gate updateNAND() { this.ram[this.NAND_OUT]=+((this.getVal(this.NAND_A)==0)||(this.getVal(this.NAND_B)==0)); /* //nand var foo=~(this.getVal(this.NAND_A)&this.getVal(this.NAND_B)); //refit into 0-255 var bar=((foo%256)+256)%256; this.ram[this.NAND_OUT]=bar; */ } run() { this.ram[this.IP]=0; while(this.getIP()<this.prog.length) { let word=this.prog[this.getIP()]; let val=word.b.getValue(this); let dest=word.a.getValue(this); this.setVal(val, dest); if(dest!=this.IP) this.incIP(); } } reset() { for(var i=0; i<256; i++) this.ram[i]=0; }}class VM255Byte{ constructor(value, isPointer) { //in case undefined this.isPointer=!!isPointer; this.setValue(value); } //functions getValue(VM){ if(this.isPointer) return VM.getVal(this.value); else return this.value; }; setValue(newVal){ //set value, keeping in 0-255 range this.value=((newVal%256)+256)%256; };}class VM255Word{ //a and b are both bytes constructor(a, b) { this.a=a; this.b=b; }}