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