多項式電卓プログラム

actionScriptの練習ということで、多項式の四則演算ができる電卓を自力で作ってみました。
かっこ()にも対応しています。
ちょっとがんばったのは、キーボードから入力しても答えを出すことができます。


まだバグがあると思われるので、どういう式がエラーを吐いたり、答えが間違っていたかを教えていただけるとうれしいです。



おそらくこういうプログラムはネットにごろごろしてると思うのですが、actionScriptの練習と、たまにはプログラムで苦しもうと思い、何も見ないで完全に自作です。
正直、最後の方は言語処理の領域に入ってしまいました。


プログラムはこちら

ソースは下に貼っておきますが無駄に長い上に見づらいです・・・

                                                                                                        • -

追記
早くもバグ発見。かっこの中がマイナスになった場合の処理がうまくいってないようです・・・原因はだいたい分かっているので近いうちに直します。

                                                                                                        • -

追記2
直しました。これで大丈夫・・・だと思うんだけど。あとは最適化というか、ソースを読みやすいようにしていきたいですね。もっと細かく関数にしたりね。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Style>
	Button {
		fontSize: 40;
	}
	TextInput{
		fontSize: 25;
	}
	TextArea{
		fontSize: 25;
	}
	
</mx:Style>

<mx:Script>
	<![CDATA[
		
		private function input(e:Event):void{
			terms.text += e.target.label;
		}
		
		private function clear():void{
			terms.text = "";
			answer.text = "";
		}
		
		private function calc():void{
			var term:String = terms.text;
			var ans:String = termsToNum(term);
			answer.text = ans;
		}
		
		private function termsToNum(term:String):String{			
			var formula:String = new String();
			var beforeFormula:String = new String();
			
			beforeFormula = removeParent(term);
			
			while(1){
				formula = removeParent(beforeFormula);
				if(beforeFormula == formula) break;
				beforeFormula = formula;
			}
			
			trace("formula:"+formula);
			
			return arithmetic(formula);
		}
		
		// (------)を外す
		private function removeParent(formula:String):String{
			
			// かっこの前後が数字かどうか
			// 数字の場合は乗算をしなければならない
			var beforeParent:Boolean = false;
			var afterParent:Boolean = false;
			
			// これに一文字ずつ入れていく
			var tmpChar:String = new String();
			var beforeChar:String = new String();
			
			// かっこの中身
			var parentheses:String = new String();
			
			// 完成させる文字列(かっこがない)
			var tmpFormula:String = new String();
			
			
			for(var i:int=0 ; i<formula.length ; i++){
				tmpChar = formula.charAt(i);
				
				if(tmpChar=="("){
					if(!isNaN(Number(beforeChar)) && i!=0){
						beforeParent = true;
					}
					break;
				}
				
				tmpFormula += tmpChar;
				beforeChar = tmpChar;
				
			}
			
			
			if(i+1 < formula.length){
				var k:int=1;
				for(var j:int=i+1 ; j<formula.length ; j++){
					tmpChar = formula.charAt(j);
					
					if(tmpChar =="("){
						k++;
					}
					else if(tmpChar ==")"){
						k--;
					}
					
					if(k==0) break;
					
				}
				
				parentheses = formula.slice(i+1,j);
				
				trace("parent:"+parentheses);
				
				parentheses = termsToNum(parentheses);
				
				if(!isNaN(Number(parentheses))){
					if(Number(parentheses)<0){
						parentheses = String(-Number(parentheses));
						trace("sendReplacePlusMinus"+tmpFormula);
						tmpFormula = replacePlusMinus(tmpFormula);
					}
				}
				
				if(beforeParent==true){
					tmpFormula += "*";
				}
				
				tmpFormula += parentheses;
				
				if(j+1 < formula.length){
					tmpChar = formula.charAt(j+1);
					
					if(!isNaN(Number(tmpChar))){
						afterParent = true;
					}
					
					if(afterParent == true){
						tmpFormula += "*";
					}
					tmpFormula += formula.slice(j+1,formula.length);
				}
			}	
			trace("tmpFormula:"+tmpFormula);
			return tmpFormula;
		}
		
		
		// 四則演算
		private function arithmetic(formula:String):String{
			
			var tmpChar:String = new String();
			//スタック(数)
			var numStack:Array = new Array();
			//スタック(算術記号)
			var calStack:Array = new Array();	
			var tmpNumber:Array = new Array();
			var beforeChar:String = new String();
			
			formula +="=";
			
			for(var i:int=0 ; i<formula.length ; i++){
				tmpChar = formula.charAt(i);
				
				//数字
				if(!isNaN(Number(tmpChar))){
					tmpNumber.push(Number(tmpChar));
					
				}
				//小数点
				else if(tmpChar=="."){
					tmpNumber.push(tmpChar);
				}
				
				//数字以外
				else{
					
					//演算記号の前の項をスタックに積む
					if(tmpNumber.length!=0){
						var tmpTerm:String =new String();
						for(var j:int=0 ; j<tmpNumber.length ; j++){
							tmpTerm += tmpNumber[j];
						}
						numStack.push(Number(tmpTerm));
						tmpNumber = new Array();
					}
					
					else if(tmpChar=="-" || tmpChar=="+"){
						numStack.push(Number(0));
					}
					
					var tmpAns:Number;
					
					// 乗算、除算
					switch(beforeChar){
					case "*":
						term2 = numStack.pop();
						term1 = numStack.pop();
						tmpAns = term1*term2;
						numStack.push(tmpAns);
					break;
					case "/":
						term2 = numStack.pop();
						term1 = numStack.pop();
						tmpAns = term1/term2;
						numStack.push(tmpAns);
					break;
					
					default:
						calStack.push(beforeChar);
					break;
					}		
					beforeChar = tmpChar;
				}
			}
			
			calStack.reverse();
			numStack.reverse();
			
			var tmpCalStack:int = calStack.length;
			var tmpCal:String = new String();
			
			// + and -
			for(var k:int=0 ; k<tmpCalStack ; k++){
				tmpCal = calStack.pop();
				
				var term1:Number = new Number();
				var term2:Number = new Number();
				
				switch(tmpCal){
					case "+":
						term1 = numStack.pop();
						term2 = numStack.pop();
						tmpAns = term1+term2;
						numStack.push(tmpAns);
					break;
					case "-":
						term1 = numStack.pop();
						term2 = numStack.pop();
						tmpAns = term1-term2;
						numStack.push(tmpAns);
					break;
				}	
				
			}
			return numStack.pop();
			
		}
		
		//beforeStrの replaceAt番目を replaceCharに書き換える
		private function charReplace(beforeStr:String,replaceAt:int,replaceChar:String):String{
			var afterStr:String = new String();
			
			afterStr += beforeStr.slice(0,replaceAt);
			afterStr += replaceChar;
			afterStr += beforeStr.slice(replaceAt+1,beforeStr.length);
			
			return afterStr;
		}
		
		private function replacePlusMinus(formula:String):String{
			var tmpChar:String = new String();
			var afterStr:String = new String();
			
			for(var i:int=formula.length ; i>=0 ; i--){
				tmpChar = formula.charAt(i);
				
				if(tmpChar =="+"){
					afterStr = charReplace(formula, i, "-");
					trace("afterStr:"+afterStr);
					return afterStr;
				}
				else if(tmpChar =="-"){
					afterStr = charReplace(formula, i, "+");
					trace("afterStr:"+afterStr);
					return afterStr;
				}
			}
			return formula;
		}
		
	]]>
</mx:Script>


	<mx:Panel x="10" y="10" width="747" height="516" layout="absolute">
		<mx:TextInput x="10" y="10" width="456" height="74" id="terms" enter="calc()"/>
		
		<mx:Button x="10" y="120" label="?" width="50" height="50"/>
		<mx:Button x="10" y="178" label="?" width="50" height="50"/>
		<mx:Button x="10" y="236" label="?" width="50" height="50"/>
		<mx:Button x="10" y="294" label="?" width="50" height="50"/>
		<mx:Button x="10" y="352" label="?" width="50" height="50"/>
		<mx:Button x="10" y="410" label="?" width="50" height="50"/>
		
		<mx:Button x="68" y="120" label="?" width="50" height="50"/>
		<mx:Button x="68" y="178" label="?" width="50" height="50"/>
		<mx:Button x="68" y="236" label="?" width="50" height="50"/>
		<mx:Button x="68" y="294" label="?" width="50" height="50"/>
		<mx:Button x="68" y="352" label="?" width="50" height="50"/>
		<mx:Button x="68" y="410" label="?" width="50" height="50"/>
		
		<mx:Button x="126" y="120" label="?" width="50" height="50"/>
		<mx:Button x="126" y="178" label="?" width="50" height="50"/>
		<mx:Button x="126" y="236" label="?" width="50" height="50"/>
		<mx:Button x="126" y="294" label="?" width="50" height="50"/>
		<mx:Button x="126" y="352" label="?" width="50" height="50"/>
		<mx:Button x="126" y="410" label="?" width="50" height="50"/>
		
		<mx:Button x="184" y="120" label="?" width="50" height="50"/>
		<mx:Button x="184" y="178" label="?" width="50" height="50"/>
		<mx:Button x="184" y="236" label="?" width="50" height="50"/>
		<mx:Button x="184" y="294" label="?" width="50" height="50"/>
		<mx:Button x="184" y="352" label="?" width="50" height="50"/>
		<mx:Button x="184" y="410" label="?" width="50" height="50"/>
		
		<mx:Button x="242" y="120" label="+" width="50" height="50" fontSize="30"  click="input(event)"/>
		<mx:Button x="242" y="178" label="-" width="50" height="50" fontSize="30"  click="input(event)"/>
		<mx:Button x="242" y="236" label="*" width="50" height="50" fontSize="30"  click="input(event)"/>
		<mx:Button x="242" y="294" label="/" width="50" height="50" fontSize="30"  click="input(event)"/>
		<mx:Button x="242" y="352" label="?" width="50" height="50"/>
		<mx:Button x="242" y="410" label="?" width="50" height="50"/>
		
		<mx:Button x="300" y="120" label="7" width="50" height="50" click="input(event)"/>
		<mx:Button x="300" y="178" label="4" width="50" height="50" click="input(event)"/>
		<mx:Button x="300" y="236" label="1" width="50" height="50" click="input(event)"/>
		<mx:Button x="300" y="294" label="0" width="50" height="50" click="input(event)"/>
		<mx:Button x="300" y="352" label="?" width="50" height="50"/>
		<mx:Button x="300" y="410" label="?" width="50" height="50"/>
		
		<mx:Button x="358" y="120" label="8" width="50" height="50" click="input(event)"/>
		<mx:Button x="358" y="178" label="5" width="50" height="50" click="input(event)"/>
		<mx:Button x="358" y="236" label="2" width="50" height="50" click="input(event)"/>
		<mx:Button x="358" y="294" label="." width="50" height="50" click="input(event)"/>
		<mx:Button x="358" y="352" label="(" width="50" height="50" click="input(event)" fontSize="30"/>
		<mx:Button x="358" y="410" label="?" width="50" height="50"/>
		
		<mx:Button x="416" y="120" label="9" width="50" height="50" click="input(event)"/>
		<mx:Button x="416" y="178" label="6" width="50" height="50" click="input(event)"/>
		<mx:Button x="416" y="236" label="3" width="50" height="50" click="input(event)"/>
		<mx:Button x="416" y="294" label="+/-" width="50" height="50" fontSize="12"/>
		<mx:Button x="416" y="352" label=")" width="50" height="50" fontSize="30" click="input(event)"/>
		<mx:Button x="416" y="410" label="C" width="50" height="50" click="clear()"/>
		
		<mx:Button x="474" y="120" label="=" width="240" height="340" id="equal" fontSize="500" click="calc()"/>
		<mx:TextArea x="474" y="11" width="240" height="73" id="answer"/>
		
	</mx:Panel>
</mx:Application>