Created
December 4, 2016 15:54
-
-
Save mohemohe/20dfc09296ab796e2e10c9791c029aa3 to your computer and use it in GitHub Desktop.
KenkovFuck 簡易インタプリター
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * KenkovFuckインタプリターの実装クラス | |
| */ | |
| export default class KenkovFuck { | |
| /** | |
| * もろもろの初期化を行う | |
| * | |
| * @param {string} [src=] ソースコード(ファイルではなく文字列) | |
| * | |
| * @public | |
| * | |
| * @return {KenkovFuck} KenkovFuckオブジェクト | |
| */ | |
| constructor(src = '') { | |
| this._idDebug = false; | |
| this._stack = []; | |
| this._mem = []; | |
| this._memPtr = 0; | |
| // ソースの改行・スペース・タブを取り除き、!区切りで命令ごとの配列にする | |
| this._src = src.replace(/\n/g, '') | |
| .replace(/\s/g, '') | |
| .replace(/\t/g, '') | |
| .split('!'); | |
| this._srcPtr = 0; | |
| this.debugLog('KenkovFuck initialized.'); | |
| } | |
| /** | |
| * デバッグ時のみログを出力する | |
| * | |
| * @private | |
| * | |
| * @param {any} 出力するオブジェクト | |
| * @param {boolean} [isDebug=this._isDebug] 弄るな | |
| * | |
| * @return {undefined} | |
| */ | |
| debugLog(obj, isDebug = this._isDebug) { | |
| if(!isDebug) { | |
| return; | |
| } | |
| if(console.debug !== undefined) { | |
| console.debug(obj); | |
| } else { | |
| console.log(obj); | |
| } | |
| } | |
| /** | |
| * 現在のインタプリターの情報を出力する | |
| * | |
| * @param {string} [isDebug=true] 弄るな | |
| * | |
| * @public | |
| * | |
| * @return {undefined} | |
| */ | |
| info(isDebug = true) { | |
| this.debugLog(`current mem: ${this.readMem()}, current ptr: ${this._memPtr}, selected src: ${this._src[this._srcPtr]}`, isDebug); | |
| this.debugLog(`mem: [${this._mem}], stack: [${this._stack}]`, isDebug); | |
| } | |
| /** | |
| * ステップ実行する | |
| * | |
| * @public | |
| * | |
| * @return {boolean} 処理を続行できるかどうか | |
| */ | |
| step() { | |
| if(this.isEndOfSrc()) { | |
| this.debugLog('end of source'); | |
| return false; | |
| } | |
| this.info(this._isDebug); | |
| const operate = this.selectOperate(); | |
| this.debugLog(`operation: ${operate.name}`); | |
| operate(this); | |
| this._srcPtr++; | |
| return true; | |
| } | |
| /** | |
| * 実行する | |
| * | |
| * @public | |
| * | |
| * @return {undefined} | |
| */ | |
| exec() { | |
| while(this.step()) { } | |
| } | |
| /** | |
| * | |
| * ソースポインターがソースコードの終端まで来ているかどうか | |
| * | |
| * @private | |
| * | |
| * @return {boolean} 終端かどうか | |
| */ | |
| isEndOfSrc() { | |
| return (this._srcPtr > this._src.length - 1 || this._src[this._srcPtr] === undefined); | |
| } | |
| /** | |
| * 実行する操作を選択する | |
| * | |
| * @private | |
| * | |
| * @return {function} | |
| */ | |
| selectOperate() { | |
| const operate = this._src[this._srcPtr]; | |
| let func; | |
| switch(operate) { | |
| case 'ゴクッ': | |
| return this.ptrPlus; | |
| case 'ズンッ': | |
| return this.ptrMinus; | |
| case 'アンッ': | |
| return this.memPlus; | |
| case 'ドピュッ': | |
| return this.memMinus; | |
| case 'モグッ': | |
| return this.print; | |
| case 'ブリッ': | |
| return this.read; | |
| case 'シュッ': | |
| return this.pushPtr; | |
| case 'ズブッ': | |
| return this.popPtr; | |
| default: | |
| return this.nop; | |
| } | |
| } | |
| /** | |
| * メモリポインターが指し示すアドレスを進める | |
| * | |
| * @private | |
| * | |
| * @return {undefined} | |
| */ | |
| ptrPlus(self) { | |
| self._memPtr++; | |
| } | |
| /** | |
| * メモリポインターが指し示すアドレスを戻す | |
| * | |
| * @private | |
| * | |
| * @return {undefined} | |
| */ | |
| ptrMinus(self) { | |
| self._memPtr--; | |
| if(self._memPtr < 0) { | |
| throw new Error('ぬるぽ'); | |
| } | |
| } | |
| /** | |
| * メモリポインターが指しているアドレスのメモリーの値を1増やす | |
| * | |
| * @private | |
| * | |
| * @return {undefined} | |
| */ | |
| memPlus(self) { | |
| self.operateMem(true); | |
| } | |
| /** | |
| * メモリポインターが指しているアドレスのメモリーの値を1減らす | |
| * | |
| * @private | |
| * | |
| * @return {undefined} | |
| */ | |
| memMinus(self) { | |
| self.operateMem(false); | |
| } | |
| /** | |
| * ポインターが指し示すメモリーの内容を1文字出力する | |
| * | |
| * @private | |
| * | |
| * @param {number} メモリアドレスを指すポインター | |
| * | |
| * @return {undefined} | |
| */ | |
| print(self) { | |
| const byte = self.readMem(self._memPtr); | |
| const char = String.fromCharCode(byte); | |
| console.log(char); | |
| } | |
| /** | |
| * ポインターが指し示すメモリーに1文字読み込む | |
| * | |
| * @param {number} メモリアドレスを指すポインター | |
| * | |
| * @return {undefined} | |
| */ | |
| read(self) { | |
| // TODO: implement | |
| } | |
| /** | |
| * スタックにソースポインターを積む | |
| * | |
| * @return {undefined} | |
| */ | |
| pushPtr(self) { | |
| self._stack.push([ | |
| self._srcPtr, | |
| null | |
| ]); | |
| } | |
| /** | |
| * スタックからソースポインターを取り出す | |
| * | |
| * @return {undefined} | |
| */ | |
| popPtr(self) { | |
| if(self._stack[self._stack.length - 1][1] === null) { | |
| self._stack[self._stack.length - 1] = [ | |
| self._stack[self._stack.length - 1][0], | |
| self._srcPtr | |
| ]; | |
| } | |
| if(self.readMem(self._memPtr) === 0) { | |
| const ptrMap = self._stack.pop(); | |
| self._srcPtr = ptrMap[1]; | |
| return; | |
| } | |
| self._srcPtr = self._stack[self._stack.length - 1][0]; | |
| } | |
| /** | |
| * なにもしない | |
| * | |
| * @return {undefined} | |
| */ | |
| nop(self) { } | |
| /** | |
| * メモリー空間をチェックし、必要であれば確保する | |
| * | |
| * @private | |
| * | |
| * @param {number} メモリアドレスを指すポインター | |
| * | |
| * @return {undefined} | |
| */ | |
| tryAllocMem() { | |
| while(this._memPtr > this._mem.length - 1) { | |
| this._mem.push(0); | |
| } | |
| } | |
| /** | |
| * メモリーから1バイト読み込む | |
| * | |
| * @private | |
| * | |
| * @param {number} メモリアドレスを指すポインター | |
| * | |
| * @return {number} メモリーの値 | |
| */ | |
| readMem() { | |
| this.tryAllocMem(this._memPtr); | |
| return this._mem[this._memPtr]; | |
| } | |
| /** | |
| * メモリーを操作する | |
| * | |
| * @private | |
| * | |
| * @param {boolean} trueで1加える falseで1減らす | |
| * @param {number} メモリアドレスを指すポインター | |
| * | |
| * @return {undefined} | |
| */ | |
| operateMem(add) { | |
| const operation = add ? 1 : -1; | |
| this.tryAllocMem(); | |
| this._mem[this._memPtr] += operation; | |
| // byteで循環 | |
| if(this._mem[this._memPtr] === 256) { | |
| this._mem[this._memPtr] = 0; | |
| } else if(this._mem[this._memPtr] === -1) { | |
| this._mem[this._memPtr] = 255; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment