逆ポーランドで遊んでみる
作ってみた
JavaScriptで、とても単純な逆ポーランドの記法の処理系を書いてみました。ちなみに足し算しかできません。最も基本的な文法は、こんな形になります。
3 4 plus
これは 3 + 4 を計算します。演算子は「+」だと面白くないので、「plus」にしてみました。もう少し複雑な計算をしてみます。
5 2 plus 11 plus
これは 5 + 2 + 11を計算します。
5 2 11 plus plus
こっちは、5 + ( 2 + 11 ) を計算します。先に ( 2 + 11 ) が計算されるのがポイントです。普段私たちが利用している中置記法では、先に計算して欲しい部分には、括弧をつける必要がありますが、ポーランド記法場合は括弧が不要です。
使い方
上で説明した構文を文字列として定義し、parse関数に渡してやると結果が返ってきます。
var str = "5 2 11 plus plus"; // 5+(2+11) alert( parse(str) ); //18
ソースコード
結構短いです。引き算、掛け算、割り算あたりはすぐに追加できるでしょう。二乗なんていう処理は、数値1つで出来るので、面白いかもしれませんね。
function init(){ //var str ="3 4 plus"; //3+4 //var str ="5 2 plus 11 plus"; //(5+2) + 11 //var str = "5 2 11 plus plus"; // 5+(2+11) var str = "5 2 11 plus plus 3 plus 4 plus 5 plus"; // 5+(2+11) + 3 + 4 + 5 alert( parse(str) ); } function parse(stream){ stream = stream.split(" "); var stack = new Array(); while(0<stream.length){ var reg1 = stream.shift(); switch(reg1){ case "plus" : var reg1 = stack.pop(); var reg2 = stack.pop(); if(!isNum(reg1) || !isNum(reg2)) throw new Error("構文にミスがあります"); stack.push(reg1 + reg2); break; default: if( isNum(reg1) ){ stack.push(parseInt(reg1)); }else throw new Error("構文にミスがあります"); break; } } if(stack.length != 1 || !isNum(stack[0]) ) throw new Error("構文にミスがあります"); return stack.pop(); } function isNum(num){ num = parseInt(num); return (typeof num == "number"); }
余談
ちなみにJavaScriptの型変換がすこし面倒でした。最初は文字列として渡しているので、ちゃんと数値に変換しないと、「+」の演算子は、文字列として連結されてしまいます。こんな風になりますので、注意してください。
"3" + "4" = "34"
追記 2010/02/02
もうちょっと改良
/** * @author Lucy */ function init(){ //var str ="3 4 add"; //3+4 //var str ="5 2 add 11 add"; //(5+2) + 11 //var str = "5 2 11 add add"; // 5+(2+11) //var str = "5 2 11 add add 3 add 4 add 5 add"; // 5+(2+11) + 3 + 4 + 5 //var str ="3 4 sub"; //3-4 //var str ="3 -4 sub"; //3-(-4) //var str ="3 4 sub 5 sub"; //3-4 -5 //var str ="3 4 5 sub sub"; // 3 - (4-5) //var str ="3 4 mul"; //3*4 //var str ="3 4 mul 5 mul"; //3*4*5 //var str ="3 4 5 mul mul"; // 3 * (4*5) //var str ="100 4 div"; // 100/4 //var str ="100 4 div 5 div"; // 100/4/5 //var str ="100 4 5 div div"; //100 / (4/5) //var str ="2 squ"; //2^2 //var str ="3 squ squ"; // 3^2^2 //var str = "2 del 3"; //3 var str = "2 3 4 5 del del del"; //2 document.write( parse(str) ); } function parse(stream){ stream = stream.split(" "); var stack = new Array(); while(0<stream.length){ var reg1 = stream.shift(); switch(reg1){ case "add" : //足し算 var reg1 = stack.pop(); var reg2 = stack.pop(); if(!isNum(reg1) || !isNum(reg2)) throw new Error("構文にミスがあります"); stack.push(reg1 + reg2); break; case "sub" : //引き算 var reg1 = stack.pop(); var reg2 = stack.pop(); if(!isNum(reg1) || !isNum(reg2)) throw new Error("構文にミスがあります"); stack.push(reg2 - reg1); break; case "mul" : //掛け算 var reg1 = stack.pop(); var reg2 = stack.pop(); if(!isNum(reg1) || !isNum(reg2)) throw new Error("構文にミスがあります"); stack.push(reg1 * reg2); break; case "div" : //割り算 var reg1 = stack.pop(); var reg2 = stack.pop(); if(!isNum(reg1) || !isNum(reg2)) throw new Error("構文にミスがあります"); stack.push( reg2 / reg1); //ゼロ割り算の計算結果はjavascriptにまかせる break; case "squ" : //二乗 var reg1 = stack.pop(); if(!isNum(reg1)) throw new Error("構文にミスがあります"); stack.push( reg1 * reg1 ); break; case "del" : //削除 stack.pop(); break; default: if( isNum(reg1) ){ stack.push(parseInt(reg1)); }else throw new Error("構文にミスがあります"); break; } } if(stack.length != 1 || !isNum(stack[0]) ) throw new Error("構文にミスがあります"); return stack.pop(); } function isNum(num){ num = parseInt(num); return (typeof num == "number"); }