/**
* Copyright codeonwort ( http://wonderfl.net/user/codeonwort )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/aTGf
*/
package {
import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
import flash.text.TextField;
import flash.display.Sprite;
public class Main extends Sprite {
private var prompt:TextField, result:TextField
private var input:TextField, output:TextField
private var tokenizer:Tokenizer
public function Main() {
// write as3 code here..
prompt = label("> ", 0, 0)
input = new TextField
input.type = "input"
input.x = prompt.width
input.width = stage.stageWidth - prompt.width - 5
input.height = prompt.height
input.border = true
input.borderColor = 0xff0000
input.addEventListener("keyDown", input_keyDown)
addChild(input)
result = label("= ", 0, prompt.height + 5)
output = new TextField
output.autoSize = "left"
output.width = stage.stageWidth - prompt.width - 5
output.x = result.width
output.y = result.y
addChild(output)
}
private function label(lbl:String, x:Number, y:Number):TextField {
var t:TextField = new TextField
t.autoSize = "left"
t.x = x
t.y = y
t.text = lbl
addChild(t)
return t
}
private function input_keyDown(e:KeyboardEvent):void {
if(e.keyCode == Keyboard.ENTER){
try{
tokenizer = new Tokenizer(new Expr(input.text))
output.text = expression().toString()
}catch(err:Error){
output.text = err.message
}
}
}
private function expression():Number {
var left:Number = term()
var t:Token
while(tokenizer.isEmpty() == false){
t = tokenizer.get()
switch(t.kind){
case '+' :
left += term()
break
case '-' :
left -= term()
break
default:
tokenizer.putback(t)
return left
}
}
return left
}
private function term():Number {
var left:Number = primary()
var t:Token
while(tokenizer.isEmpty() == false){
t = tokenizer.get()
switch(t.kind){
case '*' :
left *= primary()
break
case '/' :
var d:Number = primary()
if(d == 0) throw new Error("division by 0")
left /= d
break
default :
tokenizer.putback(t)
return left
}
}
return left
}
private function primary():Number {
var t:Token = tokenizer.get()
switch(t.kind){
case '(' :
var d:Number = expression()
t = tokenizer.get()
if(t.kind != ')') throw new Error(")가 없음")
return d
case Token.NUM :
return t.value
case '+' :
return primary()
case '-' :
return -primary()
default :
throw new Error("기본항을 찾을 수 없다")
}
}
}
}
class Expr {
private var str:String
public function Expr(s:String) {
str = ""
for(var i:int=0; i<s.length; i++){
if(s.charAt(i) != " ") str += s.charAt(i)
}
}
public function get():String {
var ch:String = str.charAt(0)
str = str.substr(1)
return ch
}
public function putback(ch:String):void {
str = ch + str
}
public function isEmpty():Boolean {
return str.length == 0
}
}
class Token {
public static const NUM:String = 'n'
public var kind:String
public var value:Number
public function Token(k:String, v:Number=NaN) {
kind = k
value = v
}
}
class Tokenizer {
private var full:Boolean = false
private var buffer:Vector.<Token>
private var expr:Expr
public function Tokenizer(e:Expr) {
expr = e
buffer = new Vector.<Token>
var char:String
var tok:Token
lbl : while(expr.isEmpty() == false){
char = expr.get()
switch(char){
case '(' : case ')' : case '+' : case '-' : case '*' : case '/' :
tok = new Token(char)
break
case '.' : case '0' : case '1' : case '2' : case '3' : case '4' :
case '5' : case '6' : case '7' : case '8' : case '9' :
// 숫자를 읽어야 한다
expr.putback(char)
tok = new Token(Token.NUM, getNumber())
break
default :
throw new Error("invalid token")
}
buffer.unshift(tok) // 토큰을 역순으로 넣는다
}
}
public function get():Token {
if(buffer.length != 0){
return buffer.pop()
}
throw new Error("buffer is empty")
}
public function isEmpty():Boolean {
return buffer.length == 0
}
private function getNumber():Number {
var str:String = ""
var ch:String
lbl : while(true){
ch = expr.get()
switch(ch){
case '.' : case '0' : case '1' : case '2' : case '3' : case '4' :
case '5' : case '6' : case '7' : case '8' : case '9' :
str += ch
break
default :
expr.putback(ch)
break lbl
}
}
var n:Number = Number(str)
if(isNaN(n)) throw new Error("invalid number representation")
return n
}
public function putback(t:Token):void {
buffer.push(t)
}
}