Rzer
31.07.2007, 19:27
Пишу модуль калькулятора на АС3 вот сам класс (может пригодится, кому надо).
package atFlashClasses.math{/*
AS3 Mathcad class
Last update: July 31, 2007 v1.1
Author: Korablyov Anatolii.
E-mail: rzer@mail.ru
Calc Constructor: mathcad.calc(Equation:String, objContainsConstAndFunc:Object)
Sample usage: mathcad.calc("-1*sin(angle*pi/180)",{angle: 20});
Standart operators: +-/*^()
Standart constants: pi,e, rnd (Number between 0 to 1)
Standart functions: sin(x),cos(x),tg(x),arcsin(x), arctg(x)
abs(x), min(x1,..xn), max(x1,..xn), ln(x)
*/
public class Mathcad {
public static var ERROR_INCORRECT_EQUATION = 1;
public static var ERROR_DIVISION_BY_ZERO = 2;
public static var ERROR_FUNCTION_NOT_FOUND = 3;
public static var ERROR_CONSTANT_NOT_FOUND = 4;
public static var ERROR_NOT_A_FUNCTION = 5;
public static var ERROR_NOT_A_CONSTANT = 6;
public static var ERROR_INCORRECT_NUMBER_OF_ARGUMENTS = 7;
public static function calc(_str,obj:Object = null){
var output:Array = []; var stack:Array = [];
var temp:String = ""; var char:String = "";
var unary:Boolean = true; var priority:uint;
var dblOpCatcher:Boolean = false;
var BraceCntr:Number=0;
/////////Преобразование в обратную польскую запись////////
mainLoop: for(var i=0;i<_str.length;i++){
char = _str.charAt(i);
switch(char){
case "-":
if (unary){ //Унарный минус? Может быть в начале строки или перед открывающей скобкой
dblOpCatcher=true;
temp+=char; unary = false; //Забираем его как число
continue mainLoop;
}
case "+": case "^": case "*": case "/":
if(dblOpCatcher){
throw new Error("Incorrect Equation string!",1);
}
dblOpCatcher=true;
unary = false; //После знака не может быть унарного минуса
if (temp) { //Записываем в выходную строку число или переменную,
output.push(temp); //если таковая стояла до знака
temp="";
}
//Перенесём все знаки большего приоритета из стека в выходную строку
while(getPriority(char) <= getPriority(stack[stack.length-1])) output.push(stack.pop());
stack.push(char); //Запишем знак в стек
break;
case "(":
BraceCntr++;
dblOpCatcher=true;
unary = true; //Следующим символом может быть унарный минус
if (temp) {
stack.push(temp+"@1("); //Все символы (не знак) стоящие до скобки - имя функции
temp=""; //где @1 - флаг-число аргументов
}else stack.push("(");
continue mainLoop;
case ",": case ")":
if (char==")"){
BraceCntr--;
if (BraceCntr<0) throw new Error ("Incorrect Equation string!",1);
}
if (char==","){
if (BraceCntr==0) throw new Error ("Incorrect Equation string!",1);
}
if(dblOpCatcher){
throw new Error("Incorrect Equation string!",1);
}
if (char==",") dblOpCatcher=true;
if (temp) {
output.push(temp);
temp="";
}
//Перенесем все знаки, которые накопилсь после "("
for(var j=stack.pop(); j.indexOf("(")< 0; j=stack.pop()) {
output.push(j);
if (stack.length==0) throw new Error("Incorrect Equation string!",1);
}
if (char==","){ //Скобка не закончилась
if (j.length==1)stack.push(j);
else {
j = j.split("@"); //Увиличим флаг-число аргументов на 1
stack.push(j[0]+"@" + (Number(j[1].substr(-2, j[1].length-1))+1) + "(");
}
unary=true;
}else if (j.length > 1) output.push(j.substr(0,j.length-1)); //Скобка закончилась
continue mainLoop;
default : //Для всех чисел и букв образуем строку до знака или конца строки
dblOpCatcher=false;
temp+=char; unary = false;
continue mainLoop;
}//End switch
}//End mainLoop
if (BraceCntr>0) throw new Error ("Incorrect Equation string!",1);
if (temp) output.push(temp);
while(stack.length>0) output.push(stack.pop()); //Переносим все оставшиеся знаки
j="";
// trace ("Обратная польская запись: " + output);
///////////Вычисление результата////////////
while(output.length>0){
j = output.shift();
if (j == "+" || j == "-" || j == "*" || j == "/" || j =="^"){
var a:Number; var b:Number;
b = getNumber(stack.pop(),obj);
a = getNumber(stack.pop(),obj);
}
switch(j){
case "+": stack.push(a+b); break;
case "-": stack.push(a-b); break;
case "*": stack.push(a*b); break;
case "/":
if (b==0) throw new Error("Division by zero!", 2);
stack.push(a/b); break;
case "^": stack.push(Math.pow(a,b)); break;
default:
if (j.indexOf("@")>= 0) stack.push(getFunction(j,stack,obj));
else stack.push(j);
}
}
return stack.pop();
}//End function
}//End class
}//End package
internal function getPriority(_str){
switch (_str){
case "^": return 3;
case "+": case "-": return 1;
case "*": case "/": return 2;
case "(": return 0;
}
}
internal function getNumber(_str,obj):Number{
var uMinus:Number = 1;
if (isNaN(Number(_str))){
if (_str.charAt()=="-"){
uMinus=-1;
_str=_str.slice(1).toLowerCase();
}
switch(_str){
case "pi": return Math.PI*uMinus;
case "e": return Math.E*uMinus;
case "rnd": return Math.random()*uMinus;
default:
try{
if (obj[_str] is Number){
return obj[_str]*uMinus;
} else if (obj[_str]==undefined){
throw new Error ("Constant '" + _str + "' was not found!",4);
}else throw new Error ( _str + "' is not a Number!", 6);
} catch(e:Error) {
throw new Error ("Constant '" + _str + "' was not found!",4);
}
}
}
return Number(_str);
}
internal function getFunction(_str,stack,obj):Number{
var args:Array = []; //Сами аргументы (стоят в стеке до оператора функции)
var args_number = _str.split("@")[1]; //Число аргументов
var func = _str.split("@")[0].toLowerCase(); //Имя функции
for (var i = 1; i<=args_number;i++){
args.unshift(getNumber(stack.pop(),obj));
}
var uMinus:Number = 1; //Переменная, фиксирующая есть ли в начале имени функции унарный минус
if (func.charAt()=="-"){
uMinus=-1;
func=func.slice(1);
}
var f:Function;
var r:Number;
switch(func){ //Применим к функции массив аргуметов
case "sin": f = Math.sin; break;
case "cos": f = Math.cos; break;
case "abs": f = Math.abs; break;
case "arcsin": f = Math.asin; break;
case "arctg": f = Math.atan; break;
case "tg": f = Math.tan; break;
case "ln": f = Math.log; break;
case "min": f = Math.min; break;
case "max": f = Math.max; break;
default:
try{
if (obj[func] is Function){ //Нестандартная функция из переданного объекта
f=obj[func];
} else if (obj[func]==undefined){
throw new Error ("Function '" + func + "' was not found!", 3);
}else throw new Error (func + "' is not a Function!", 5);
} catch(e:Error) {
throw new Error ("Function '" + func + "' was not found!", 3);
}
}
try{
r = f.apply(null,args)*uMinus;
}catch(e:Error){
throw new Error ("Incorect number of arguments in function '"+ func +"'!", 7);
}
return r;
}
Как добавить к нему возникновение ошибок (Чтобы можно было отлавливать их через try...catch из вне) вместо трейса? Используя что-то вроде:
try{
Mathcad.calc("3/0");
}catch(e:Error){
trace(e.message + ' ' + e.errorID);
}
package atFlashClasses.math{/*
AS3 Mathcad class
Last update: July 31, 2007 v1.1
Author: Korablyov Anatolii.
E-mail: rzer@mail.ru
Calc Constructor: mathcad.calc(Equation:String, objContainsConstAndFunc:Object)
Sample usage: mathcad.calc("-1*sin(angle*pi/180)",{angle: 20});
Standart operators: +-/*^()
Standart constants: pi,e, rnd (Number between 0 to 1)
Standart functions: sin(x),cos(x),tg(x),arcsin(x), arctg(x)
abs(x), min(x1,..xn), max(x1,..xn), ln(x)
*/
public class Mathcad {
public static var ERROR_INCORRECT_EQUATION = 1;
public static var ERROR_DIVISION_BY_ZERO = 2;
public static var ERROR_FUNCTION_NOT_FOUND = 3;
public static var ERROR_CONSTANT_NOT_FOUND = 4;
public static var ERROR_NOT_A_FUNCTION = 5;
public static var ERROR_NOT_A_CONSTANT = 6;
public static var ERROR_INCORRECT_NUMBER_OF_ARGUMENTS = 7;
public static function calc(_str,obj:Object = null){
var output:Array = []; var stack:Array = [];
var temp:String = ""; var char:String = "";
var unary:Boolean = true; var priority:uint;
var dblOpCatcher:Boolean = false;
var BraceCntr:Number=0;
/////////Преобразование в обратную польскую запись////////
mainLoop: for(var i=0;i<_str.length;i++){
char = _str.charAt(i);
switch(char){
case "-":
if (unary){ //Унарный минус? Может быть в начале строки или перед открывающей скобкой
dblOpCatcher=true;
temp+=char; unary = false; //Забираем его как число
continue mainLoop;
}
case "+": case "^": case "*": case "/":
if(dblOpCatcher){
throw new Error("Incorrect Equation string!",1);
}
dblOpCatcher=true;
unary = false; //После знака не может быть унарного минуса
if (temp) { //Записываем в выходную строку число или переменную,
output.push(temp); //если таковая стояла до знака
temp="";
}
//Перенесём все знаки большего приоритета из стека в выходную строку
while(getPriority(char) <= getPriority(stack[stack.length-1])) output.push(stack.pop());
stack.push(char); //Запишем знак в стек
break;
case "(":
BraceCntr++;
dblOpCatcher=true;
unary = true; //Следующим символом может быть унарный минус
if (temp) {
stack.push(temp+"@1("); //Все символы (не знак) стоящие до скобки - имя функции
temp=""; //где @1 - флаг-число аргументов
}else stack.push("(");
continue mainLoop;
case ",": case ")":
if (char==")"){
BraceCntr--;
if (BraceCntr<0) throw new Error ("Incorrect Equation string!",1);
}
if (char==","){
if (BraceCntr==0) throw new Error ("Incorrect Equation string!",1);
}
if(dblOpCatcher){
throw new Error("Incorrect Equation string!",1);
}
if (char==",") dblOpCatcher=true;
if (temp) {
output.push(temp);
temp="";
}
//Перенесем все знаки, которые накопилсь после "("
for(var j=stack.pop(); j.indexOf("(")< 0; j=stack.pop()) {
output.push(j);
if (stack.length==0) throw new Error("Incorrect Equation string!",1);
}
if (char==","){ //Скобка не закончилась
if (j.length==1)stack.push(j);
else {
j = j.split("@"); //Увиличим флаг-число аргументов на 1
stack.push(j[0]+"@" + (Number(j[1].substr(-2, j[1].length-1))+1) + "(");
}
unary=true;
}else if (j.length > 1) output.push(j.substr(0,j.length-1)); //Скобка закончилась
continue mainLoop;
default : //Для всех чисел и букв образуем строку до знака или конца строки
dblOpCatcher=false;
temp+=char; unary = false;
continue mainLoop;
}//End switch
}//End mainLoop
if (BraceCntr>0) throw new Error ("Incorrect Equation string!",1);
if (temp) output.push(temp);
while(stack.length>0) output.push(stack.pop()); //Переносим все оставшиеся знаки
j="";
// trace ("Обратная польская запись: " + output);
///////////Вычисление результата////////////
while(output.length>0){
j = output.shift();
if (j == "+" || j == "-" || j == "*" || j == "/" || j =="^"){
var a:Number; var b:Number;
b = getNumber(stack.pop(),obj);
a = getNumber(stack.pop(),obj);
}
switch(j){
case "+": stack.push(a+b); break;
case "-": stack.push(a-b); break;
case "*": stack.push(a*b); break;
case "/":
if (b==0) throw new Error("Division by zero!", 2);
stack.push(a/b); break;
case "^": stack.push(Math.pow(a,b)); break;
default:
if (j.indexOf("@")>= 0) stack.push(getFunction(j,stack,obj));
else stack.push(j);
}
}
return stack.pop();
}//End function
}//End class
}//End package
internal function getPriority(_str){
switch (_str){
case "^": return 3;
case "+": case "-": return 1;
case "*": case "/": return 2;
case "(": return 0;
}
}
internal function getNumber(_str,obj):Number{
var uMinus:Number = 1;
if (isNaN(Number(_str))){
if (_str.charAt()=="-"){
uMinus=-1;
_str=_str.slice(1).toLowerCase();
}
switch(_str){
case "pi": return Math.PI*uMinus;
case "e": return Math.E*uMinus;
case "rnd": return Math.random()*uMinus;
default:
try{
if (obj[_str] is Number){
return obj[_str]*uMinus;
} else if (obj[_str]==undefined){
throw new Error ("Constant '" + _str + "' was not found!",4);
}else throw new Error ( _str + "' is not a Number!", 6);
} catch(e:Error) {
throw new Error ("Constant '" + _str + "' was not found!",4);
}
}
}
return Number(_str);
}
internal function getFunction(_str,stack,obj):Number{
var args:Array = []; //Сами аргументы (стоят в стеке до оператора функции)
var args_number = _str.split("@")[1]; //Число аргументов
var func = _str.split("@")[0].toLowerCase(); //Имя функции
for (var i = 1; i<=args_number;i++){
args.unshift(getNumber(stack.pop(),obj));
}
var uMinus:Number = 1; //Переменная, фиксирующая есть ли в начале имени функции унарный минус
if (func.charAt()=="-"){
uMinus=-1;
func=func.slice(1);
}
var f:Function;
var r:Number;
switch(func){ //Применим к функции массив аргуметов
case "sin": f = Math.sin; break;
case "cos": f = Math.cos; break;
case "abs": f = Math.abs; break;
case "arcsin": f = Math.asin; break;
case "arctg": f = Math.atan; break;
case "tg": f = Math.tan; break;
case "ln": f = Math.log; break;
case "min": f = Math.min; break;
case "max": f = Math.max; break;
default:
try{
if (obj[func] is Function){ //Нестандартная функция из переданного объекта
f=obj[func];
} else if (obj[func]==undefined){
throw new Error ("Function '" + func + "' was not found!", 3);
}else throw new Error (func + "' is not a Function!", 5);
} catch(e:Error) {
throw new Error ("Function '" + func + "' was not found!", 3);
}
}
try{
r = f.apply(null,args)*uMinus;
}catch(e:Error){
throw new Error ("Incorect number of arguments in function '"+ func +"'!", 7);
}
return r;
}
Как добавить к нему возникновение ошибок (Чтобы можно было отлавливать их через try...catch из вне) вместо трейса? Используя что-то вроде:
try{
Mathcad.calc("3/0");
}catch(e:Error){
trace(e.message + ' ' + e.errorID);
}