I wrote, with the help of The Art of Java by Herbert Schildt and James Holmes, a custom parser that evaluates a numerical expression like: "10+32/2". So the following is the code:
package com.soliduscode.eleanya; import java.util.logging.Handler; /** * * * @author ukaku * */ public class Parser { final int NONE =0; final int DELIMITER =1; final int VARIABLE = 2; final int NUMBER = 3; final int SYNTAX = 0; final int UNBALPARENS=1; final int NOEXP = 2; final int DIVBYZERO=3; final String EOE = "\0"; /**the expression*/ private String exp; /** expression index */ private int expIndex; /**Current token*/ private String token; /**The token type*/ private int tokenType; /** * Return the next token in the expression */ private void getToken(){ //clear values initially tokenType = NONE; token = ""; //check for endl of expression if(expIndex == exp.length()){ token = EOE; return; } //skip over white spaces while(expIndex < exp.length() && Character.isWhitespace(exp.charAt(expIndex))) ++expIndex; //trailing white spaces ends expression if(expIndex == exp.length()){ token = EOE; return; } if(isDelimiter(exp.charAt(expIndex))){ token += exp.charAt(expIndex); expIndex++; tokenType = DELIMITER; }else if(Character.isLetter(exp.charAt(expIndex))){ while(expIndex < exp.length() && !isDelimiter(exp.charAt(expIndex))){ token+=exp.charAt(expIndex); expIndex++; if(expIndex >= exp.length()) break; } tokenType = VARIABLE; }else if(Character.isDigit(exp.charAt(expIndex))){ while(expIndex < exp.length() && !isDelimiter(exp.charAt(expIndex))){ token += exp.charAt(expIndex); expIndex++; if(expIndex > exp.length()) break; } tokenType = NUMBER; }else{ token = EOE; return; } } /** * Returns the value of the expression * * * @param expstr the expression to evaulate * @return the value of the expression * @throws ParserException */ public double evaluate(String expstr) throws ParserException { double result; exp = expstr;//+" "; expIndex= 0; getToken(); if(token.equals(EOE)) handleError(NOEXP); //no expression present result = evaluateAdditionSubstraction(); if(!token.equals(EOE)) handleError(SYNTAX); return result; } private double evaluateAdditionSubstraction() throws ParserException{ char op; double result; double partialResult; result = evaluateMultDivMod(); while((op = token.charAt(0)) == '+' || op == '-'){ getToken(); partialResult = evaluateMultDivMod(); switch(op){ case '-': result = result - partialResult; break; case '+': result = result + partialResult; break; } } return result; } private double evaluateMultDivMod() throws ParserException { char op; double result; double partialResult; result = evaluteExponent(); while((op = token.charAt(0)) == '*' ||op == '/' || op == '%'){ getToken(); partialResult = evaluteExponent(); switch(op){ case '*': result = result * partialResult; break; case '/': if(partialResult == 0.0){ handleError(DIVBYZERO); } result = result / partialResult; break; case '%': if(partialResult == 0.0) handleError(DIVBYZERO); result = result % partialResult; break; } } return result; } //process exponent private double evaluteExponent() throws ParserException{ double result; double partialResult; double ex; int t; result = evaluateUnary(); if(token.equals("^")){ getToken(); partialResult = evaluteExponent(); ex = result; if(partialResult == 0.0){ result = 1.0; }else{ for(t=(int)partialResult-1; t>0; t--){ result = result * ex; } } } return result; } //evaluate a unarry + or - private double evaluateUnary() throws ParserException{ double result; String op; op=""; if((tokenType == DELIMITER) && token.equals("+") || token.equals("-")){ op = token; getToken(); //get the other unary } result = evaluateParenthesis(); if(op.equals("-")) result = -result; return result; } //process parenthesized expression private double evaluateParenthesis() throws ParserException{ double result; if(token.equals("(")){ getToken(); result = evaluateAdditionSubstraction(); if(!token.equals(")")) handleError(UNBALPARENS); getToken(); }else result = atom(); return result; } //get the value of a number private double atom() throws ParserException { double result = 0.0; switch(tokenType){ case NUMBER: try{ result = Double.parseDouble(token); }catch(NumberFormatException exc){ handleError(SYNTAX); } getToken(); break; default: handleError(SYNTAX); break; } return result; } private void handleError(int error) throws ParserException { String[] e = { "Syntax Error", "nbalanced parentheses", "No Expression Present", "Division by zero" }; throw new ParserException(e[error]); } /** * Determin is character c is a delimiter symbol * @param c * @return */ private boolean isDelimiter(char c){ if((" +-/*%^=()".indexOf(c) != -1)){ return true; } return false; } public static void main(String arg[]){ Parser parser = new Parser(); try { System.out.println("Hello world " + parser.evaluate("10*10^2")); } catch (ParserException e) { e.printStackTrace(); } } }
Comments
Post a Comment