In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

電卓!

Simple Recursive Descent Parsing
see also: http://fxp.hp.infoseek.co.jp/arti/parser.html
電卓!
* パーサの練習として下のページ見ながら電卓作った!
* wonderflのコードには載ってないけど、AS3Unit使ってテストがんがん使った。
* めんどくさかったのが、数値かどうかの判定と、パーサーエラーの処理。
* 
* 使えるやつ
* 整数、少数、()、+-/*
* 16進数、指数
* @see http://d.hatena.ne.jp/nitoyon/20090128/as3_simple_parser
* @see http://www.ibm.com/developerworks/jp/java/library/j-scala10248.html
* @see http://d.hatena.ne.jp/ActionScript/20090512/as3_exponentiation
* @author coppieee
Get Adobe Flash player
by coppieee 14 Dec 2009
    Embed
// forked from nitoyon's Simple Recursive Descent Parsing
// Simple Recursive Descent Parsing
// see also: http://fxp.hp.infoseek.co.jp/arti/parser.html
/**
 * 電卓!
 * パーサの練習として下のページ見ながら電卓作った!
 * wonderflのコードには載ってないけど、AS3Unit使ってテストがんがん使った。
 * めんどくさかったのが、数値かどうかの判定と、パーサーエラーの処理。
 * 
 * 使えるやつ
 * 整数、少数、()、+-/*
 * 16進数、指数
 * @see http://d.hatena.ne.jp/nitoyon/20090128/as3_simple_parser
 * @see http://www.ibm.com/developerworks/jp/java/library/j-scala10248.html
 * @see http://d.hatena.ne.jp/ActionScript/20090512/as3_exponentiation
 * @author coppieee
 */
package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
	
	public class Main extends Sprite{
		public function Main(){
			var tf:TextField = new TextField();
			tf.x = 20;
			tf.y = 20;
			tf.width = 200;
			tf.height = 20;
			tf.multiline = false;
			tf.border = true;
			tf.type = TextFieldType.INPUT;
			addChild(tf);
			tf.addEventListener(Event.CHANGE, function(e:Event):void {
				try{
					out.text = Parser.parse(tf.text) + "";
				}catch(e:ParserError) {
					out.htmlText = e.codeToHtmlString();
				}
			});
			var out:TextField = new TextField();
			out.height = tf.height;
			out.width = tf.width;
			out.y = tf.height + tf.y;
			out.x = tf.x;
			addChild(out);
			stage.focus = tf;
			scaleX = 2;
			scaleY = 2;
		
			tf.text = "-1.1 + 2 * (0xf + 1e+3)";
			tf.dispatchEvent(new Event(Event.CHANGE));
		}
	}
}
//package  
//{
	//public 
	class Parser{
		public static function parse(source:String):Number {
			var parser:Parser = new Parser(source);
			return parser.input();
		}
		public function Parser(source:String) {	
			_source = source;
		}
		
		public function get source():String {  return _source; }
		private var _source:String;
		public function get currentSource():String {
			return _source.substr(index); 
		}
		public function get currentChar():String {
			if (_source.length <= index) { return null; }
			return _source.charAt(index);
		}
		public function get index():int { return _index; }
		private var _index:int;
		
		//input ::= ws expr ws eoi
		public function input():Number {
			ws();
			var result:Number = expr();
			ws();
			if (!isEoi) {
				throw new ParserError("not eoi",index,source);
			}
			return result;
		}
		private function get isEoi():Boolean {
			return _index == source.length;
		}
		//expr ::= ws term { ws (+|-) ws term}
		public function expr():Number {
			ws();
			var result:Number = term();
			while(true){
				ws();
				var resultAdd:Function;
				if (currentChar == "+") {
					resultAdd = function():void { result += term(); }
				}else if (currentChar == "-") {
					resultAdd = function():void { result -= term(); }
				}else {
					break;
				}
				var exprIndex:int = _index;
				_index++;
				ws();
				if (isEoi) {
					throw new ParserError("+-",exprIndex,source);
				}
				resultAdd();
			}
			return result;
		}
		//term ::= ws fact { ws (*|/) ws fact}
		public function term():Number {
			ws();
			var result:Number = fact();
			while (true) {
				ws();
				var resultAdd:Function;
				if (currentChar == "*") {
					resultAdd = function():void { result *= fact(); }
				} else if(currentChar =="/") {
					resultAdd = function():void { result /= fact(); }
				}else {
					break;
				}
				var termIndex:int = _index;
				_index++;
				ws();
				if (isEoi) {
					throw new ParserError("*/",termIndex,source);
				}
				resultAdd();
			}
			return result;
		}
		//fact ::= ws (expr) | -|+ ws fact | ws  number
		public function fact():Number {
			ws();
			if (currentChar == "(") {
				var parentheseIndex:int = index;
				_index ++;
				ws();
				if (_index == _source.length) {
					throw new ParserError("()error",parentheseIndex,source);
				}
				
				var result:Number = expr();
				if (currentChar == ")") {
					_index++;
					return result;
				}
				throw new ParserError("()error",parentheseIndex,source);
			}else if (currentChar == "-") {
				var subIndex:int = _index;
				_index++;
				ws();
				if (isEoi) { throw new ParserError("-",subIndex,source); }
				return - fact();
			}else if (currentChar == "+") {
				var addIndex:int = _index;
				_index++;
				ws();
				if (isEoi) { throw new ParserError("+",addIndex,source); }
				return fact();
			}else {
				return number();
			}
		}
		//ws ::= [{\s|\t|\n|\r}]
		public function ws():void {
			var w:Object = /\s+/.exec(currentSource);
			if (w != null && w.index==0) {
				_index += w[0].length;
			}
		}
		//number ::= 0x{dgt|a-f} |
		// ([{dgt}].{dgt} | [{{dgt})(e[-|+] {dgt}})] |
		// | .{dgt}
		
		public function number():Number {
			function getNum():Number{
				var n16:Object = /0x[\da-f]+/i.exec(currentSource);
				if (n16 != null && n16.index == 0) {
					_index += n16[0].length;
					return parseInt(n16[0]);
				}
				var n:Object = 
		/(((\d*\.\d+)|(\d+))(e(\-|\+)?\d+)?)|(\.\d+)/i.
					exec(currentSource);
				if (n != null && n.index == 0) {
					_index += n[0].length;
					return parseFloat(n[0]);
				}
				throw new ParserError("numberError index:"+index+",source:"+source, index, source);
			}
			var result:Number = getNum();
			if (currentChar != null &&
				!currentChar.match(/[\(\)\s\+\-\*\/]/i)) {
				throw new ParserError("numberError:",index,source);
			}
			return result;
		}
	}
//}
//package {
	//public 
	class ParserError extends Error {
		public function get col():int { return _col; }
		private var _col:int;
		public function get source():String { return _source; }
		private var _source:String;
		
		public function ParserError(message:String,col:int,source:String ) {
			_col = col;
			_source = source;
			super(message);
		}
		public function codeToHtmlString():String {
			var str:String = "";
			str += (_col == 0) ? "" : _source.substr(0, _col);
			str += "<font color='#FF0000'>" + _source.charAt(_col) + "</font>";
			str += (_col == _source.length) ? "" : _source.substr(_col + 1);
			return str;
		}
	}
//}