Całość piszę w Eclipse IDE for Java Developers, i z tego co znalazłem jre 7. Tak apropos całości kodu. Wygląda on w ten sposób:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
class Tokens{
public int position;
public int type;
public String value = "";
public Tokens(int position, int type, String value) {
this.position = position;
this.type = type;
this.value = value;
}
public String toString(){
return String.valueOf(value);
}
}
public class MExp {
private String _input = "";
public ArrayList<Tokens> _tokens = new ArrayList<Tokens>();
public ArrayList<String> _rpn = new ArrayList<String>();
private Map<String,Double> _vars = new HashMap<String,Double>();
{
_vars.put("pi",new Double(Math.PI));
_vars.put("e",new Double(Math.E));
}
/**
* @var error - tablica opisująca ostatni błąd składniowy w wyrażeniu
*
*/
public Map<String,Object> error = new HashMap<String,Object>();
{
error.put("nr",new Integer(0));
error.put("position",new Integer(0));
error.put("value",new String(""));
error.put("expected",new String(""));
}
public double result = 0;
//private int position;
static private Map<String,String> _errstr = new HashMap<String,String>();
{
_errstr.put("invalid_opr","%s\n%s\nSYNTAX ERROR: Invalid operator '%s' at position '%d'\n");
_errstr.put("invalid_var","%s\n%s\nSYNTAX ERROR: Undefined variable '%s' at position '%d'\n");
_errstr.put("invalid_number","%s\n%s\nSYNTAX ERROR: Invalid number format '%s' at position '%d'\n");
_errstr.put("unexpected_char","%s\n%s\nSYNTAX ERROR: Unexpected '%s' at position '%d'. Expecting '%s'\n");
_errstr.put("unexpected_end","%s\n%s\nSYNTAX ERROR: Unexpected 'END_OF_EXPRESSION'. Expecting '%s'\n");
};
static private Map<String,String> _union = new HashMap<String,String>();
{
_union.put("]", "[");
_union.put(")", "(");
}
static private Map<String,String> _union2 = new HashMap<String,String>();
{
_union.put( "[" , "]" );
_union.put( "(" , ")" );
}
static private String[] _valid_operators = {
"/",
"!",
"*",
"-",
"+",
"(",
")",
"[",
"]",
"|",
"^",
"%"
};
static private String[] _function_lists = {
"abs",
"acos",
"asin",
"atan",
"cbrt",
"ceil",
"cos",
"cosh",
"exp",
"expm1",
"floor",
"log10",
"log",
"log1p",
"rint",
"round",
"signum",
"sin",
"sinh",
"sqrt",
"tan",
"tanh",
"ulp"
};
static int ME_NUM=1;
static int ME_STR=2;
static int ME_OPR=4;
static int ME_FUN=8;
MExp(String exp){
this._input = exp.replace(" ", "");
}
MExp(String exp , Map<String,Double> vars){
this._input=exp.replace(" ", "");
if(vars.isEmpty()!=true)
this._vars.putAll(vars);
}
public MExp addVar(String name,double value){
this._vars.put(name, Double.valueOf(value));
return this;
}
public String result(int scale){
this.lexer();
if(this.syntax_checker(_tokens) == null) return this.errstr();
if(!this.reverse_polish_notation(_tokens)) return this.errstr();
//this.countExp(_rpn);
return String.format("%." + scale + "f",this.result);
}
public static String repeat(String s, int times) {
if (times <= 0) return "";
else if (times % 2 == 0) return repeat(s+s, times/2);
else return s + repeat(s+s, times/2);
}
public ArrayList<Tokens> lexer(){
String str = this._input;
ArrayList<Tokens> out = new ArrayList<Tokens>();
char v;
String tmp = "";
Tokens token;
for(int x = 0; x < str.length(); x++){
v = str.charAt(x);
if(Ctype.isPunct(v) && v != '_'){
token = new Tokens( x, MExp.ME_OPR, String.valueOf(v));
out.add(token);
}
else if(Ctype.isDigit(v)){
tmp = String.valueOf(v);
token = new Tokens( x, MExp.ME_NUM ,"");
for(;(x+1 < str.length()) && (Ctype.isDigit(str.charAt(x+1)) || str.charAt(x+1) == 'e' || str.charAt(x+1) == 'E' || str.charAt(x+1) == '.') ; ){
tmp += String.valueOf( str.charAt( ++x ) );
}
token.value = tmp;
out.add(token);
}
else if(Ctype.isAlpha(v) || v == '_'){
tmp = String.valueOf(v);
token = new Tokens( x, MExp.ME_STR ,tmp);
for(;((x+1 < str.length()) && (Ctype.isAlnum(str.charAt(x+1)) || str.charAt(x+1) == '_' ));){
tmp += String.valueOf(str.charAt(++x));
}
token.value = tmp;
out.add(token);
}
}
return _tokens = out;
}
public ArrayList<Tokens> syntax_checker(ArrayList<Tokens> tokens){
for(int x=0; x < tokens.size(); x++){
if(((tokens.get(x).type==MExp.ME_OPR) && (Arrays.binarySearch(MExp._valid_operators, tokens.get(x).value))==-1)){
this.error(0x01, tokens.get(x).position, tokens.get(x).value, "");
return null;
}
else if(tokens.get(x).type==MExp.ME_STR){
System.out.println(tokens.get(x));
if( (tokens.size() <= x+1) || (tokens.size() > x+1 && (tokens.get(x+1).value.compareTo("(") != 0 && tokens.get(x+1).value.compareTo("[") != 0 && tokens.get(x+1).value.compareTo("|") != 0 ))){
tokens.get(x).type=MExp.ME_NUM;
Double y;
y = this._vars.get(tokens.get(x).value);
if(y != null){
tokens.get(x).value=y.toString();
}
else{
this.error(0x03, tokens.get(x).position, tokens.get(x).value, "");
return null;
}
}
else{
tokens.get(x).type=MExp.ME_FUN;
if(!MExp.function_exists(tokens.get(x).value)){
this.error(0x04, tokens.get(x).position, tokens.get(x).value, "");
return null;
}
}
}
}
return _tokens = tokens;
}
public boolean reverse_polish_notation(ArrayList<Tokens> tokens){
Stack<String> stack = new Stack<String>();
_tokens = tokens;
int[] level = {0,0,0};
Tokens v;
String tmp = "";
int i = 0;
String r = "";
for(int x=0; x < this._tokens.size(); x++){
v = this._tokens.get(x);
if(v.type == MExp.ME_NUM){
this._rpn.add(v.value);
}
else if(v.type == MExp.ME_OPR){
if(v.value.compareTo("[") == 0 || v.value.compareTo("(") == 0){
stack.add(v.value);
level[MExp.btype(v.value)]++;
}
else if(v.value.compareTo("]") == 0||v.value.compareTo(")") == 0){
if(level[MExp.btype(MExp._union.get(v.value))] == 0){
this.error(0x11, v.position, v.value, "");
return false;
}
else{
if(level[MExp.btype("(")] == level[MExp.btype("[")])tmp = "-1";
tmp = (tmp.length() == 0 ? (level[MExp.btype("(")] > level[MExp.btype("[")]?"(":"[") : tmp);
switch(tmp){
case "(":
i = stack.size();
r = stack.get(--i);
while((r != "(" || r != "[") && i > 0){
r = stack.get(--i);
}
if(r == MExp._union.get(v.value)){
String last = stack.pop();
while(last != r ^ last != null){
this._rpn.add(last);
if(!stack.isEmpty())
last = stack.pop();
else
last = null;
}
level[MExp.btype(r)]--;
}
else if(MExp._union.get(v.value) != tmp){
this.error(0x12, v.position, v.value, MExp._union2.get(tmp));
return false;
}
else{
String last = stack.pop();
while(last != tmp ^ last != null){
this._rpn.add(last);
if(!stack.isEmpty())
last = stack.pop();
else
last = null;
}
level[MExp.btype(tmp)]--;
}
break;
case "[":
i = stack.size();
r = stack.get(--i);
while(r != "(" || r != "["){
r = stack.get(--i);
}
if(r == MExp._union.get(v.value)){
String last = stack.pop();
while(last != r ^ last != null){
this._rpn.add(last);
if(!stack.isEmpty())
last = stack.pop();
else
last = null;
}
level[MExp.btype(r)]--;
}
else if(MExp._union.get(v.value) != tmp){
this.error(0x13, v.position, v.value, MExp._union2.get(tmp));
return false;
}
else{
String last = stack.pop();
while(last != tmp ^ last != null){
this._rpn.add(last);
if(!stack.isEmpty())
last = stack.pop();
else
last = null;
}
level[MExp.btype(tmp)]--;
}
break;
case "-1":
i = stack.size();
r = stack.get(--i);
while(r != "(" || r != "["){
r = stack.get(--i);
}
if(r == MExp._union.get(v.value)){
String last = stack.pop();
while(last != r ^ last != null){
this._rpn.add(last);
if(!stack.isEmpty())
last = stack.pop();
else
last = null;
}
level[MExp.btype(r)]--;
}
else{
this.error(0x14, v.position, v.value, MExp._union2.get(r));
return false;
}
break;
}
}
}
else{
if(v.value.compareTo("-") == 0 && (x-1 < 0 || tokens.get(x-1).type == MExp.ME_OPR)) this._rpn.add("0");
int pr = MExp.operator_priority(v.value);
String last;
if(!stack.isEmpty())
last = stack.pop();
else
last = null;
if(last == null){
stack.add(v.value);
}
else if(pr >= MExp.operator_priority(last)){
stack.add(last);
stack.add(v.value);
}
else if(last.compareTo("(") == 0 || last.compareTo("[") == 0){
stack.add(last);
stack.add(v.value);
}
else{
if(last != null && last != "")
this._rpn.add(last);
while(last != null && pr > MExp.operator_priority(last)){
this._rpn.add(last);
if(!stack.isEmpty())
last = stack.pop();
else
last = null;
}
stack.add(v.value);
}
}
}
else if(v.type == MExp.ME_FUN){
if(v.value.compareTo("-") == 0 && (x-1 < 0 || tokens.get(x-1).type == MExp.ME_OPR)) this._rpn.add("0");
int pr = MExp.operator_priority(v.value);
String last = stack.isEmpty() ? null : stack.pop();
if(last == null){
stack.add(v.value);
}
else if(pr >= MExp.operator_priority(last)){
stack.add(last);
stack.add(v.value);
}
else if(last == "(" || last == "["){
stack.add(last);
stack.add(v.value);
}
else{
this._rpn.add(last);
while(last != null && pr > MExp.operator_priority(last)){
this._rpn.add(last);
last = stack.pop();
}
stack.add(v.value);
}
}
/*/ dev info
System.out.println("wejście: \t" + v.value);
System.out.println("level1: \t" + level[0]);
System.out.println("level2: \t" + level[1]);
System.out.println("stos: \t\t" + stack.toString());
System.out.println("wyjście: \t"+ _rpn.toString() + "\n");
// dev info - end*/
}
if(level[0] != 0 || level[1] != 0){
i = stack.size();
r = stack.get(--i);
while((r != "(" || r!= "[") && i > 0){
r = stack.get(--i);
}
this.error(0x15, this._input.length(), "END_OF_EXPRESSION", MExp._union2.get(r));
return false;
}
while(!stack.isEmpty())
this._rpn.add(stack.pop());
return true;
}
private static boolean function_exists(String name){
return Arrays.binarySearch(MExp._function_lists, name)!=-1?true:false;
}
private static int btype(String bracket){
int r;
switch(bracket){
case "(": r = 0; break;
case "[": r = 1; break;
case "|": r = 2; break;
default : r = -1; break;
};
return r;
}
public String replaceAt(int i,String s,char c){
char[] o;
o = s.toCharArray();
o[i] = c;
return String.valueOf(o);
}
public void error(int nr, int position, String value,String expected){
error.put("nr",new Integer(nr));
error.put("position",new Integer(position));
error.put("value",value);
error.put("expected",expected);
}
public String errstr(){
String space;
space = replaceAt(Integer.parseInt(this.error.get("position").toString()),MExp.repeat(" ",this._input.length()+1),'|');
String ret = "";
switch(Integer.parseInt(this.error.get("nr").toString())){
case 0x00:
ret = "OK";
break;
case 0x01:
ret = String.format(MExp._errstr.get("invalid_opr"), this._input, String.valueOf(space), this.error.get("value"), Integer.parseInt(this.error.get("position").toString())+1);
break;
case 0x02:
ret = String.format(MExp._errstr.get("invalid_number"), this._input, String.valueOf(space), this.error.get("value"), Integer.parseInt(this.error.get("position").toString())+1);
break;
case 0x03:
ret = String.format(MExp._errstr.get("invalid_var"), this._input, String.valueOf(space), this.error.get("value"), Integer.parseInt(this.error.get("position").toString())+1);
break;
case 0x04:
ret = String.format(MExp._errstr.get("invalid_fun"), this._input, String.valueOf(space), this.error.get("value"), Integer.parseInt(this.error.get("position").toString())+1);
break;
case 0x11:
case 0x12:
case 0x13:
case 0x14:
ret = String.format(MExp._errstr.get("unexpected_char"), this._input, String.valueOf(space), this.error.get("value"), Integer.parseInt(this.error.get("position").toString())+1,this.error.get("expected"));
break;
case 0x15:
ret = String.format(MExp._errstr.get("unexpected_end"), this._input, String.valueOf(space),this.error.get("expected"));
break;
}
return ret;
}
private static int operator_priority(String value){
switch(value){
case "": return -1;
case "[":return -1;
case "(":return -1;
case "+":return 0;
case "-":return 0;
case "*":return 1;
case "/":return 1;
case "%":return 2;
case "^":return 2;
case "!":return 3;
default: return 256;
}
}
private double mod(double x, double mod)
{
double i = Math.floor( x / mod );
double x2 = i * mod;
return x - x2;
}
private double factorial(double n){
n = Math.abs( Math.floor(n) );
if( n==0 || n==1)
return 1;
return n * factorial( n - 1 );
}
private static boolean isDouble(String str){
try{
Double.parseDouble(str);
return true;
}
catch (Exception e){
return false;
}
}
public static Double call_math_function(String name, Double param){
Double ret = null;
switch(name){
case "abs": ret = new Double(Math.abs(param.doubleValue())); break;
case "acos": ret = new Double(Math.acos(param.doubleValue())); break;
case "asin": ret = new Double(Math.asin(param.doubleValue())); break;
case "atan": ret = new Double(Math.atan(param.doubleValue())); break;
case "cbrt": ret = new Double(Math.cbrt(param.doubleValue())); break;
case "ceil": ret = new Double(Math.ceil(param.doubleValue())); break;
case "cos": ret = new Double(Math.cos(param.doubleValue())); break;
case "cosh": ret = new Double(Math.cosh(param.doubleValue())); break;
case "exp": ret = new Double(Math.exp(param.doubleValue())); break;
case "expm1": ret = new Double(Math.expm1(param.doubleValue())); break;
case "floor": ret = new Double(Math.floor(param.doubleValue())); break;
case "log10": ret = new Double(Math.log10(param.doubleValue())); break;
case "log": ret = new Double(Math.log(param.doubleValue())); break;
case "log1p": ret = new Double(Math.log1p(param.doubleValue())); break;
case "rint": ret = new Double(Math.rint(param.doubleValue())); break;
case "round": ret = new Double(Math.round(param.doubleValue())); break;
case "signum": ret = new Double(Math.signum(param.doubleValue())); break;
case "sin": ret = new Double(Math.sin(param.doubleValue())); break;
case "sinh": ret = new Double(Math.sinh(param.doubleValue())); break;
case "sqrt": ret = new Double(Math.sqrt(param.doubleValue())); break;
case "tan": ret = new Double(Math.tan(param.doubleValue())); break;
case "tanh": ret = new Double(Math.tanh(param.doubleValue())); break;
case "ulp": ret = new Double(Math.ulp(param.doubleValue())); break;
}
return ret;
}
public double countExp(ArrayList<String> rpn){
Stack<String> stack = new Stack<String>();
for(int x = 0; x< rpn.size(); x++){
String v = rpn.get(x);
double a,b;
if(MExp.isDouble(v)){
stack.add(v);
}
else if(Ctype.isPunct(v)){
switch(v){
case "*":
b = Double.parseDouble(stack.pop());
a = Double.parseDouble(stack.pop());
stack.add(String.valueOf( a * b ));
break;
case "^":
b = Double.parseDouble(stack.pop());
a = Double.parseDouble(stack.pop());
stack.add(String.valueOf(Math.pow(a, b)));
break;
case "/":
b = Double.parseDouble(stack.pop());
a = Double.parseDouble(stack.pop());
stack.add(String.valueOf( a / b));
break;
case "+":
b = Double.parseDouble(stack.pop());
a = Double.parseDouble(stack.pop());
stack.add(String.valueOf( a + b ));
break;
case "-":
b = Double.parseDouble(stack.pop());
a = Double.parseDouble(stack.pop());
stack.add(String.valueOf( a - b ));
break;
case "%":
b = Double.parseDouble(stack.pop());
a = Double.parseDouble(stack.pop());
stack.add(String.valueOf(this.mod(a, b)));
break;
case "!":
a = Double.parseDouble(stack.pop());
stack.add(String.valueOf(this.factorial(a)));
break;
}
}
else if(Ctype.isAlnum(v)){
a = Double.parseDouble(stack.pop());
stack.add(String.valueOf(MExp.call_math_function(v, a)));
}
}
this.result = Double.parseDouble(stack.pop());
return 0;
}
}
I to jest własnie owa klasa, do tego jeszcze używana wewnątrz klasa :
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Ctype {
final static boolean isLower(String str){
Pattern a = Pattern.compile("\\p{Lower}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isUpper(String str){
Pattern a = Pattern.compile("\\p{Upper}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isAlpha(String str){
Pattern a = Pattern.compile(".*\\p{Alpha}");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isPunct(String str){
Pattern a = Pattern.compile("\\p{Punct}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isGraph(String str){
Pattern a = Pattern.compile("\\p{Graph}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isDigit(String str){
Pattern a = Pattern.compile("\\p{Digit}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isPrint(String str){
Pattern a = Pattern.compile("\\p{Print}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isAlnum(String str){
Pattern a = Pattern.compile("\\p{Alnum}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isCntrl(String str){
Pattern a = Pattern.compile("\\p{Cntrl}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isSpace(String str){
Pattern a = Pattern.compile("\\p{Space}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isBlank(String str){
Pattern a = Pattern.compile("\\p{Blank}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isXDigit(String str){
Pattern a = Pattern.compile("\\p{XDigit}*");
Matcher m = a.matcher(str);
return m.matches();
}
final static boolean isASCII(String str){
Pattern a = Pattern.compile("\\p{ASCII}*");
Matcher m = a.matcher(str);
return m.matches();
}
/* For Char type */
final static boolean isLower(char str){
Pattern a = Pattern.compile("\\p{Lower}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isUpper(char str){
Pattern a = Pattern.compile("\\p{Upper}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isAlpha(char str){
Pattern a = Pattern.compile(".*\\p{Alpha}");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isPunct(char str){
Pattern a = Pattern.compile("\\p{Punct}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isGraph(char str){
Pattern a = Pattern.compile("\\p{Graph}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isDigit(char str){
Pattern a = Pattern.compile("\\p{Digit}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isPrint(char str){
Pattern a = Pattern.compile("\\p{Print}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isAlnum(char str){
Pattern a = Pattern.compile("\\p{Alnum}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isCntrl(char str){
Pattern a = Pattern.compile("\\p{Cntrl}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isSpace(char str){
Pattern a = Pattern.compile("\\p{Space}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isBlank(char str){
Pattern a = Pattern.compile("\\p{Blank}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isXDigit(char str){
Pattern a = Pattern.compile("\\p{XDigit}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
final static boolean isASCII(char str){
Pattern a = Pattern.compile("\\p{ASCII}*");
Matcher m = a.matcher(String.valueOf(str));
return m.matches();
}
}
a main służy na razie tylko do testowania klasy. Z analizy to wszystko w klasie działa mi zgodnie z moimi założeniami aż do momentu własnie owej felernej metody countExp() (sorki za różnice nazw ale poprzednia jej nazwa to własnie count()) zresztą możecie sobie sprawdzić biorąc w komentarz tą metodę i wpisać np: "sin(pi)*cos(pi)"
Nie rozumiem co takiego strasznego jest w tym kodzie??