/* org.manalith.ircbot.plugin.calc/CalcTokenAnalyzer.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.util.regex.Pattern; import org.manalith.ircbot.plugin.calc.TokenUnit.TokenSubtype; import org.manalith.ircbot.plugin.calc.TokenUnit.TokenType; import org.manalith.ircbot.plugin.calc.exceptions.EmptyTokenStreamException; import org.manalith.ircbot.plugin.calc.exceptions.TokenAnalysisException; public class CalcTokenAnalyzer { private String tokenStream; public CalcTokenAnalyzer(String mathExpr) { tokenStream = mathExpr; } public TokenType getTokenType(String tokenString) { TokenType type = TokenType.Unknown; // Regex patterns for recognizing integer if (Pattern.matches("(0|(0|1)+)(B|b)", tokenString) || Pattern.matches("0[1-7][0-7]*", tokenString) || Pattern.matches("(0|-?[1-9][0-9]*)", tokenString) || Pattern.matches("0x([0-9a-fA-F]*)", tokenString)) type = TokenType.Integer; // Regex pattern for recognizing floating point else if (Pattern .matches("(-?[0-9]+)(\\.[0-9]+)?(([Ee](-?[1-9][0-9]*))|f)?", tokenString)) type = TokenType.FlPoint; // Regex pattern for recognizing operator else if (Pattern.matches("\\+|\\-|\\*|\\/|\\%|\\^|\\!", tokenString)) type = TokenType.Operatr; // Regex patterns for recognizing parenthesis // to change priority of calculation else if (Pattern.matches("\\(", tokenString) || Pattern.matches("\\)", tokenString)) type = TokenType.Parents; // Regex patterns for recognizing parentheses // to preprocess for the function else if (Pattern.matches("sin|cos|tan|arcsin|arccos|arctan", tokenString)) type = TokenType.TriangleFunc; else if (Pattern.matches("to(bin|oct|dec|hex)", tokenString)) type = TokenType.BaseConvFunc; else if (Pattern.matches("sqrt", tokenString)) type = TokenType.MathematFunc; return type; } public TokenSubtype getTokenSubtype(String tokenString, TokenType type) { TokenSubtype result = TokenSubtype.Unknown; switch (type.value()) { case 1: // Integer if (Pattern.matches("(0|(0|1)+)(B|b)", tokenString)) result = TokenSubtype.Binary; else if (Pattern.matches("0[1-7][0-7]*", tokenString)) result = TokenSubtype.Octal; else if (Pattern.matches("(0|-?[1-9][0-9]*)", tokenString)) result = TokenSubtype.Decimal; else if (Pattern.matches("0x([0-9a-fA-F]*)", tokenString)) result = TokenSubtype.Hexadec; break; case 2: // FlPoint if (Pattern.matches("(-?[0-9]+)(\\.[0-9]+)?f", tokenString)) result = TokenSubtype.SpFltPoint; else if (Pattern.matches("(-?[0-9]+)(\\.[0-9]+)", tokenString)) result = TokenSubtype.DpFltPoint; else if (Pattern.matches( "(-?[0-9]+)(\\.[0-9]+)?([Ee](-?[1-9][0-9]*))", tokenString)) result = TokenSubtype.ExpFltPoint; break; case 3: // Operator switch(tokenString) { case "+": result = TokenSubtype.Plus; break; case "-": result = TokenSubtype.Minus; break; case "*": result = TokenSubtype.Times; break; case "/": result = TokenSubtype.Divide; break; case "%": result = TokenSubtype.Modulus; break; case "^": result = TokenSubtype.Power; break; case "!": result = TokenSubtype.Factorial; break; } break; case 4: // Parenthesis switch(tokenString) { case "(": result = TokenSubtype.Left_Parenthesis; break; case ")": result = TokenSubtype.Righ_Parenthesis; break; } break; case 5: // Triangular function switch(tokenString) { case "sin": result = TokenSubtype.Sine; break; case "cos": result = TokenSubtype.Cosine; break; case "tan": result = TokenSubtype.Tangent; break; case "arcsin": result = TokenSubtype.ArcSine; break; case "arccos": result = TokenSubtype.ArcCosine; break; case "arctan": result = TokenSubtype.ArcTangent; break; } break; case 6: // Base conversion switch(tokenString) { case "tobin": result = TokenSubtype.ToBin; break; case "tooct": result = TokenSubtype.ToOct; break; case "todec": result = TokenSubtype.ToDec; break; case "tohex": result = TokenSubtype.ToHex; break; } break; case 7: // Mathematical function if (tokenString.equals("sqrt")) result = TokenSubtype.Sqrt; } return result; } public TokenArray getTokenArray() throws TokenAnalysisException, EmptyTokenStreamException { TokenArray result = new TokenArray(); int stringLength = tokenStream.length(); if (stringLength == 0) throw new EmptyTokenStreamException(); String temp = ""; TokenType currentType = TokenType.Unknown; TokenType checkedType = TokenType.Unknown; // init. for (int i = 0; i < stringLength; i++) { // x"." if (tokenStream.charAt(i) == '.') { checkedType = TokenType.FlPoint; currentType = TokenType.FlPoint; temp = temp.concat(tokenStream.substring(i, i + 1)); continue; } // 0.001 "e" or 0xnnnne if ((tokenStream.charAt(i) == 'e' || tokenStream.charAt(i) == 'E')) { if (getTokenSubtype(temp, currentType) == TokenSubtype.Decimal) { currentType = TokenType.FlPoint; temp = temp.concat(tokenStream.substring(i, i + 1)); continue; } else { // hexa decimal, ExpFltPoint or function temp = temp.concat(tokenStream.substring(i, i + 1)); continue; } } // " 0x " if ((tokenStream.charAt(i) == 'x') && currentType == TokenType.Integer) { temp = temp.concat(tokenStream.substring(i, i + 1)); continue; } if (tokenStream.charAt(i) == '-') { if (temp.length() == 0 && i == 0) { temp = temp.concat(tokenStream.substring(i, i + 1)); currentType = getTokenType(temp); checkedType = currentType; continue; } if (temp.length() == 0 && result.getToken(result.getSize() - 1).getTokenType() != TokenType.Operatr) { // operator temp = temp.concat(tokenStream.substring(i, i + 1)); currentType = getTokenType(temp); TokenSubtype tsType = getTokenSubtype(temp, currentType); TokenUnit newUnit = new TokenUnit(currentType, tsType, temp); result.addToken(newUnit); currentType = TokenType.Unknown; temp = ""; continue; } else if (currentType == TokenType.FlPoint && (temp.charAt(temp.length() - 1) == 'e' || temp .charAt(temp.length() - 1) == 'E')) { // unary mark for exponential temp = temp.concat(tokenStream.substring(i, i + 1)); continue; } } if (tokenStream.charAt(i) == ' ') { // add token if current point meets separator(white space) currentType = getTokenType(temp); TokenSubtype tsType = getTokenSubtype(temp, currentType); TokenUnit newUnit = new TokenUnit(currentType, tsType, temp); result.addToken(newUnit); // reset temp = ""; checkedType = TokenType.Unknown; currentType = TokenType.Unknown; // and ignore white space continue; } temp = temp.concat(tokenStream.substring(i, i + 1)); if (i == 0) { // unary operator if (temp.equals("-")) { continue; } currentType = getTokenType(temp); checkedType = currentType; } else if (i == 1) { checkedType = getTokenType(temp); if (currentType != checkedType) { if (checkedType == TokenType.Unknown) { temp = temp.substring(0, temp.length() - 1); // if selected string is empty. if (temp.equals("")) throw new TokenAnalysisException(); TokenSubtype tsType = getTokenSubtype(temp, currentType); // if selected string is unknown type of token. if (currentType == TokenType.Unknown && tsType == TokenSubtype.Unknown) throw new TokenAnalysisException(); TokenUnit newUnit = new TokenUnit(currentType, tsType, temp); result.addToken(newUnit); currentType = TokenType.Unknown; temp = ""; i--; } else { currentType = checkedType; } } } else { checkedType = getTokenType(temp); if (currentType != checkedType) { if (checkedType == TokenType.Unknown) { temp = temp.substring(0, temp.length() - 1); // if selected string is empty if (temp.equals("")) throw new TokenAnalysisException(); TokenSubtype tsType = getTokenSubtype(temp, currentType); // if selected string is unknown type of token. if (currentType == TokenType.Unknown && tsType == TokenSubtype.Unknown) throw new TokenAnalysisException(); TokenUnit newUnit = new TokenUnit(currentType, tsType, temp); result.addToken(newUnit); temp = ""; currentType = TokenType.Unknown; i--; } else { currentType = checkedType; } } } } TokenSubtype tsType = getTokenSubtype(temp, currentType); // if selected string is unknown type of token. if (currentType == TokenType.Unknown && tsType == TokenSubtype.Unknown) throw new TokenAnalysisException(); TokenUnit newUnit = new TokenUnit(currentType, tsType, temp); result.addToken(newUnit); return result; } }