flash on 2010-5-12

by hycro
♥0 | Line 226 | Modified 2010-05-12 02:11:48 | MIT License
play

ActionScript3 source code

/**
 * Copyright hycro ( http://wonderfl.net/user/hycro )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/rJNY
 */

package
{
	import com.bit101.components.InputText;
	import com.bit101.components.PushButton;
	import com.bit101.components.TextArea;
	
	import flash.display.Sprite;
	import flash.events.DataEvent;
	import flash.events.Event;
	
	public class BrainfuckInterpreterMain extends Sprite
	{
		private var _outputField:TextArea;
		private var _inputField:InputText;
		private var _commitButton:PushButton;
		private var _codeField:TextArea;
		private var _runButton:PushButton;
		
		private const helloworld:String = "+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.";
			
		public function BrainfuckInterpreterMain()
		{
			// コード入力フィールド
			_codeField = new TextArea(this, 0, 0, helloworld);
			_codeField.width = stage.stageWidth;
			_codeField.height = 150;
			
			// 実行ボタン
			_runButton = new PushButton(this, 0, _codeField.height, "RUN", run);
			_runButton.width = stage.stageWidth;
			
			// 入力確定ボタン
			_commitButton = new PushButton(this, 0, 0, "input", commit);
			_commitButton.x = stage.stageWidth - _commitButton.width;
			_commitButton.y = stage.stageHeight - _commitButton.height;
			_commitButton.enabled = false;
			
			// 入力フィールド
			_inputField = new InputText(this, 0, _commitButton.y);
			_inputField.height = _commitButton.height;
			_inputField.width = _commitButton.x;
			_inputField.enabled = false;
			_inputField.maxChars = 1;
			
			// 出力フィールド
			_outputField = new TextArea(this, 0, _runButton.y + _runButton.height);
			_outputField.width = stage.stageWidth;
			_outputField.height = stage.stageHeight - _codeField.height - _runButton.height - _commitButton.height;
			_outputField.text = "";
			_outputField.editable = false;
			
			addEventListener(BrainfuckInterpreter.INPUT, onInput);
			addEventListener(BrainfuckInterpreter.OUTPUT, onOutput);
			addEventListener(BrainfuckInterpreter.FINISH, onFinish);
		}
		
		// インタープリタ
		private var _interpreter:BrainfuckInterpreter;
		
		// プログラム実行
		private function run(event:Event):void {
			if (_codeField.text.length > 0) {
				_outputField.text = "";
				_inputField.text = "";
				_interpreter = new BrainfuckInterpreter(_codeField.text, this);
				_interpreter.start();
			}
		}
		
		// 入力
		private function commit(event:Event):void {
			if (_inputField.text.length > 0) {
				_interpreter.input(_inputField.text.charCodeAt());
				_commitButton.enabled = false;
				_inputField.enabled = false;
			}
		}
		
		// 入力要求時
		private function onInput(event:Event):void {
			_commitButton.enabled = true;
			_inputField.enabled = true;
			_inputField.text = "";
		}
		
		// 出力要求時
		private function onOutput(event:DataEvent):void {
			_outputField.text += event.data;
			_interpreter.notify();
		}
		
		// プログラム終了時
		private function onFinish(event:Event):void {
			_outputField.text += "\n[end]";
		}
	}
}
import flash.events.DataEvent;
import flash.events.Event;
import flash.events.IEventDispatcher;

import org.libspark.thread.EnterFrameThreadExecutor;
import org.libspark.thread.Thread;
import org.libspark.thread.ThreadState;


class BrainfuckInterpreter extends Thread {
	/** データ入力時に送出するイベントの名前 */
	public static const INPUT:String = "jp.crz.hycro.brainfuck.BrainfuckInterpreter:INPUT";
	/** データ出力時に送出するイベントの名前 */
	public static const OUTPUT:String = "jp.crz.hycro.brainfuck.BrainfuckInterpreter:OUTPUT";
	/** プログラムの終了時に送出するイベントの名前 */
	public static const FINISH:String = "jp.crz.hycro.brainfuck.BrainfuckInterpreter:FINISH";
	
	private static const MEMORY_SIZE:uint = 3000;
	
	// メモリ
	private var _memory:Vector.<uint>;
	// メモリを指すポインタ
	private var _pointer:int;
	// プログラムコード
	private var _code:String;
	// 現在処理しているプログラムコードの位置
	private var _curr:int;
	// 現在のステップ数
	private var _numSteps:uint;
	// 1フレーム当たりに実行するステップ数
	private var _stepsPerFrame:uint;
	// インタープリタからの入出力要求を受け取るオブジェクト
	private var _io:IEventDispatcher;

	/**
	 * コンストラクタ
	 *
	 * @param io インタープリタからの入出力要求を受け取るオブジェクト
	 */
	public function BrainfuckInterpreter(code:String, io:IEventDispatcher, stepsPerFrame:uint=100):void {
		_code = code;
		_io = io;
		
		_memory = new Vector.<uint>(MEMORY_SIZE);
		_pointer = 0;
		_curr = -1;
		
		_stepsPerFrame = stepsPerFrame;
		
		if (!Thread.isReady) {
			Thread.initialize(new EnterFrameThreadExecutor);
		}
	}
	
	public function set stepsPerFrame(value:uint):void {
		_stepsPerFrame = value;
	}
	
	protected override function run():void {
		loop();
	}
	
	/**
	 * メインループ。
	 * 
	 */
	private function loop():void {
		var count:uint = 0;
		var endFlag:Boolean = false;
		
		while (count < _stepsPerFrame && state == ThreadState.RUNNABLE) {
			count++;
			if (!step()) {
				endFlag = true;
				break;
			}
		}
		if (!endFlag) {
			next(loop);
		} else {
			_io.dispatchEvent(new Event(FINISH));
		}
	}
	
	/**
	 * 処理を1ステップ進めます。
	 * 
	 * @return プログラムの終端に達している場合はfalse
	 */
	private function step():Boolean {
		var char:String;
		switch (char = getNext()) {
			case ">":
				_incrementPointer();
				break;
			case "<":
				_decrementPointer();
				break;
			case "+":
				_incrementValue();
				break;
			case "-":
				_decrementValue();
				break;
			case ".":
				_output();
				break;
			case ",":
				_input();
				break;
			case "[":
				_forward();
				break;
			case "]":
				_backward();
				break;
			case "":
				return false;
			default :
				trace("undefined token : ", char, char.charCodeAt());
		}
		return true;
	}
	
	private function getNext():String {
		var char:String;
		do {
			char = _code.charAt(++_curr);
			if (char == null) {
				return null;
			}
		} while (char == " " || char == "\n" || char == "\t");
		
		return char;
	}
	
	private function _incrementPointer():void {
		_pointer++;
		
		if (_pointer > MEMORY_SIZE) {
			trace("out of memory");
		}
	}
	
	private function _decrementPointer():void {
		_pointer--;
		
		if (_pointer < 0) {
			trace("out of memory");
		}
	}
	
	private function _incrementValue():void {
		_memory[_pointer]++;
	}
	
	private function _decrementValue():void {
		_memory[_pointer]--;
	}
	
	private function _input():void {
		wait();
		_io.dispatchEvent(new Event(INPUT));
	}
	
	private function _output():void {
		wait();
		_io.dispatchEvent(new DataEvent(OUTPUT, false, false, String.fromCharCode(_memory[_pointer])));
	}
	
	private function _forward():void {
		if (_memory[_pointer] == 0) {
			var count:uint = 1;
			var char:String;
			while (count != 0) {
				char = _code.charAt(++_curr);
				if (char == "[") {
					count++;
				} else if (char == "]") {
					count--;
				}
			}
			_curr++;
		}
	}
	
	private function _backward():void {
		if (_memory[_pointer] != 0) {
			var count:uint = 1;
			var char:String;
			while (count != 0) {
				char = _code.charAt(--_curr);
				if (char == "]") {
					count++;
				} else if (char == "[") {
					count--;
				}
			}
		}
	}
	
	public function input(value:uint):void {
		notify();
		_memory[_pointer] = value;
	}
}