Skip to content

Instantly share code, notes, and snippets.

@mohemohe
Created December 4, 2016 15:54
Show Gist options
  • Select an option

  • Save mohemohe/20dfc09296ab796e2e10c9791c029aa3 to your computer and use it in GitHub Desktop.

Select an option

Save mohemohe/20dfc09296ab796e2e10c9791c029aa3 to your computer and use it in GitHub Desktop.
KenkovFuck 簡易インタプリター
/**
* 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