/*
org.manalith.ircbot.plugin.calc/ParseTreeUnit.java
ManalithBot - An open source IRC bot based on the PircBot Framework.
Copyright (C) 2011 Seong-ho, Cho <darkcircle.0426@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.manalith.ircbot.plugin.calc;
import java.math.BigInteger;
import org.manalith.ircbot.plugin.calc.TokenUnit.TokenSubtype;
import org.manalith.ircbot.plugin.calc.TokenUnit.TokenType;
import org.manalith.ircbot.plugin.calc.exceptions.InvalidOperatorUseException;
import org.manalith.ircbot.plugin.calc.exceptions.NotImplementedException;
public class ParseTreeUnit {
protected TokenUnit node;
protected ParseTreeUnit left;
protected ParseTreeUnit right;
public void setNode(TokenUnit node) {
this.node = node;
}
public TokenUnit getNode() {
if (node != null)
return node;
else
return null;
}
public void setLeftLeapNode(TokenUnit newNode) {
left = new ParseTreeUnit();
left.setNode(newNode);
}
public TokenUnit getLeftLeapNode() {
if (left != null)
return left.getNode();
else
return null;
}
public void setRightLeapNode(TokenUnit newNode) {
right = new ParseTreeUnit();
right.setNode(newNode);
}
public TokenUnit getRightLeapNode() {
if (right != null)
return right.getNode();
else
return null;
}
public void addLeftSubtree(ParseTreeUnit newTree) {
left = new ParseTreeUnit();
left = newTree;
}
public ParseTreeUnit getLeftSubtree() {
return left;
}
public void addRightSubtree(ParseTreeUnit newTree) {
right = new ParseTreeUnit();
right = newTree;
}
public ParseTreeUnit getRightSubtree() {
return right;
}
public void removeLeftSubtree() {
left = null;
}
public void removeRightSubtree() {
right = null;
}
public void preorder() {
System.out.println(getNode());
if (left != null)
left.preorder();
if (right != null)
right.preorder();
}
public BigInteger Factorial(BigInteger n) {
if (n.compareTo(new BigInteger("1")) == 0)
return n;
else
return n.multiply(Factorial(n.subtract(new BigInteger("1"))));
}
public String getResultType() {
String leftStr = "";
String rightStr = "";
if (left != null)
leftStr = left.getResultType();
if (right != null)
rightStr = right.getResultType();
if (node.getTokenType() == TokenType.TriangleFunc
|| node.getTokenSubtype() == TokenSubtype.Sqrt)
return "FlPoint";
else if (node.getTokenType() == TokenType.Integer
|| node.getTokenType() == TokenType.FlPoint)
return node.getTokenType().toString();
else {
if ((leftStr.equals("Integer") && rightStr.equals("Integer") || leftStr
.equals("Integer") && rightStr.equals(""))
|| leftStr.equals("") && rightStr.equals("Integer"))
return "Integer";
else if (leftStr.equals("") && rightStr.equals(""))
return "";
else
return "FlPoint";
}
}
public String getIntFpResult() throws NotImplementedException {
String result = "";
String data = "";
String valstr = "";
int len = 0;
BigInteger leftVal = new BigInteger("0");
BigInteger rightVal = new BigInteger("0");
BigInteger valint = new BigInteger("0");
switch (node.getTokenType().value()) {
case 1:
switch (node.getTokenSubtype().value()) {
case 3: // decimal
result = node.getTokenString();
break;
case 1: // binary
data = node.getTokenString();
len = data.length();
// ignore last 'b'
for (int i = 0; i < len - 1; i++) {
valint.multiply(new BigInteger("2"));
valint.add(new BigInteger(
Integer.toString(data.charAt(i) - '0')));
}
result = valint.toString();
break;
case 2: // octal
data = node.getTokenString();
len = data.length();
// ignore first '0'
for (int i = 1; i < len; i++) {
valint.multiply(new BigInteger("8"));
valint.add(new BigInteger(
Integer.toString(data.charAt(i) - '0')));
}
result = valint.toString();
break;
case 4: // hex
data = node.getTokenString();
len = data.length();
for (int i = 2; i < len; i++) {
valint.multiply(new BigInteger("16"));
if (data.charAt(i) >= '0' && data.charAt(i) <= '9')
valint.add(new BigInteger(Integer.toString(data
.charAt(i) - '0')));
else if (data.charAt(i) >= 'a' && data.charAt(i) <= 'f')
valint.add(new BigInteger(Integer.toString(data
.charAt(i) - 'a' + 10)));
else if (data.charAt(i) >= 'A' && data.charAt(i) <= 'F')
valint.add(new BigInteger(Integer.toString(data
.charAt(i) - 'A' + 10)));
}
result = valint.toString();
break;
}
case 3: // operator
if (left != null)
leftVal = new BigInteger(left.getIntFpResult());
if (right != null)
rightVal = new BigInteger(right.getIntFpResult());
switch (node.getTokenSubtype().value()) {
case 8: // plus
result = leftVal.add(rightVal).toString();
break;
case 9: // minus
result = leftVal.subtract(rightVal).toString();
break;
case 10: // multiply
result = leftVal.multiply(rightVal).toString();
break;
case 11: // divide
if (rightVal.equals(new BigInteger("0")))
throw new ArithmeticException("/ by zero");
if (leftVal.mod(rightVal).equals(new BigInteger("0")))
result = leftVal.divide(rightVal).toString();
else {
double t0 = leftVal.doubleValue();
double t1 = rightVal.doubleValue();
result = Double.toString(t0 / t1);
}
break;
case 12: // modulus
if (rightVal.equals(new BigInteger("0")))
throw new ArithmeticException("/ by zero");
result = leftVal.mod(rightVal).toString();
break;
case 13: // power
result = leftVal.pow(rightVal.intValue()).toString();
break;
case 14: // factorial
result = Factorial(leftVal).toString();
break;
}
break;
case 6: // base conversion function
if (right != null)
rightVal = new BigInteger(right.getIntFpResult());
switch (node.getTokenSubtype().value()) {
case 23: // bin
while (rightVal.compareTo(new BigInteger("2")) >= 0) {
valstr = rightVal.mod(new BigInteger("2")).toString()
+ valstr;
rightVal = rightVal.divide(new BigInteger("2"));
}
valstr = rightVal.add(new BigInteger(valstr)).toString() + "b";
result = valstr;
break;
case 24: // octal
while (rightVal.compareTo(new BigInteger("8")) >= 0) {
valstr = rightVal.mod(new BigInteger("8")).toString()
+ valstr;
rightVal = rightVal.divide(new BigInteger("8"));
}
valstr = "0" + rightVal.toString() + valstr;
result = valstr;
break;
case 25: // decimal
result = rightVal.toString();
break;
case 26: // hex
BigInteger temp = new BigInteger("0");
while (rightVal.compareTo(new BigInteger("16")) >= 0) {
temp = rightVal.mod(new BigInteger("16"));
if (temp.compareTo(new BigInteger("10")) < 0)
valstr = temp.toString() + valstr;
else
valstr = Character.toString((char) (temp.subtract(
new BigInteger("10")).intValue() + 'A'))
+ valstr;
rightVal = rightVal.divide(new BigInteger("16"));
}
if (rightVal.compareTo(new BigInteger("10")) < 0)
valstr = "0x" + rightVal.toString() + valstr;
else
valstr = "0x"
+ Character.toString((char) (rightVal.subtract(
new BigInteger("10")).intValue() + 'A'))
+ valstr;
result = valstr;
break;
}
}
return result;
}
public String getFpResult() throws InvalidOperatorUseException {
String result = "";
String data = "";
int len = 0;
BigInteger val = new BigInteger("0");
double leftVal = 0.0;
double rightVal = 0.0;
switch (node.getTokenType().value()) {
case 2: // floating-point
switch (node.getTokenSubtype().value()) {
case 3: // decimal
data = node.getTokenString();
result = Double.toString(Integer.parseInt(data));
break;
case 1: // binary
data = node.getTokenString();
len = data.length();
// ignore last 'b'
for (int i = 0; i < len - 1; i++) {
val.multiply(new BigInteger("2"));
val.add(new BigInteger(Integer.toString(data.charAt(i) - '0')));
}
result = Double.toString(val.doubleValue());
break;
case 2: // octal
data = node.getTokenString();
len = data.length();
// ignore first '0'
for (int i = 1; i < len; i++) {
val.multiply(new BigInteger("8"));
val.add(new BigInteger(Integer.toString(data.charAt(i) - '0')));
}
result = Double.toString(val.doubleValue());
break;
case 4: // hex
data = node.getTokenString();
len = data.length();
for (int i = 2; i < len; i++) {
val.multiply(new BigInteger("16"));
if (data.charAt(i) >= '0' && data.charAt(i) <= '9')
val.add(new BigInteger(Integer.toString(data.charAt(i) - '0')));
if (data.charAt(i) >= 'a' && data.charAt(i) <= 'f')
val.add(new BigInteger(Integer.toString(data.charAt(i) - 'a' + 10)));
if (data.charAt(i) >= 'A' && data.charAt(i) <= 'F')
val.add(new BigInteger(Integer.toString(data.charAt(i) - 'A' + 10)));
}
result = Double.toString(val.doubleValue());
break;
case 5: // single-precision floating point
data = node.getTokenString();
result = Double.toString(Float.parseFloat(data));
break;
case 6: // double-precision floating point
data = node.getTokenString();
result = Double.toString(Double.parseDouble(data));
break;
case 7: // exponential floating point
data = node.getTokenString();
result = Double.toString(Double.parseDouble(data));
break;
}
break;
case 3: // operator
if (left != null)
leftVal = Double.parseDouble(left.getFpResult());
if (right != null)
rightVal = Double.parseDouble(right.getFpResult());
switch (node.getTokenSubtype().value()) {
case 8: // plus
result = Double.toString(leftVal + rightVal);
break;
case 9: // minus
result = Double.toString(leftVal - rightVal);
break;
case 10: // multiply
result = Double.toString(leftVal * rightVal);
break;
case 11: // divide
result = Double.toString(leftVal / rightVal);
break;
case 12: // modulus
throw new InvalidOperatorUseException();
case 13: // power
result = Double.toString(Math.pow(leftVal, rightVal));
break;
case 14: // factorial
if (left.getNode().getTokenType().equals(TokenType.Integer))
result = Factorial(
new BigInteger(left.getNode().getTokenString()
.split(".")[0])).toString();
else
throw new InvalidOperatorUseException();
}
break;
case 5: // triangular function
if (right != null)
rightVal = Double.parseDouble(right.getFpResult());
switch (node.getTokenSubtype().value()) {
case 17: // sine
result = Double.toString(Math.sin(rightVal / 180.0 * Math.PI));
break;
case 18: // cosine
result = Double.toString(Math.cos(rightVal / 180.0 * Math.PI));
break;
case 19: // tangent
result = Double.toString(Math.tan(rightVal / 180.0 * Math.PI));
break;
case 20: // arcsine
result = Double.toString(Math.asin(rightVal / 180.0 * Math.PI));
break;
case 21: // arccosine
result = Double.toString(Math.acos(rightVal / 180.0 * Math.PI));
break;
case 22: // arctangent
result = Double.toString(Math.atan(rightVal / 180.0 * Math.PI));
break;
}
break;
case 6: // base conversion function
throw new InvalidOperatorUseException();
case 7: // mathematical function
if (right != null)
rightVal = Double.parseDouble(right.getFpResult());
if (node.getTokenSubtype().equals(TokenSubtype.Sqrt))
result = Double.toString(Math.sqrt(rightVal));
break;
}
return result;
}
}