Skip to main content
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

Popular posts from this blog

Creating local variables In Assembly

Lets go over how to create local variables inside of a pure assembly source code. Much like always, you will start with a *.asm file that looks like this: source code SECTION .data SECTION .bss SECTION .text global main ;make main available to operating system(os) main: ;create the stack frame push ebp push mov ebp, esp ;destroy the stack frame mov esp, ebp pop ebp ret So, the above is the general layout of an NASM source file.  Our goal here is to create a local variable inside of the main method.  The only way to create a local variable is by using the stack.  Why?  Because we can only declare variable in storage locations and the only available storage locations are: text, bss, and data.  However, text section is only for code, so it is out of the question.  The bss and data sections are appealing, but to declare our "local" variable in these sections will defeat the purpose of these varia...

NASM Programming

Many of you, if you are like me, might be interested in how assembly works.  You will be very surprised that assembly is very very easy, especially after you write a couple of simple programs.  But don't get me wrong, you will be frustrated at first, however that frustration, if you channel it right, will lead to serious life long learning and will give you a deeper appreciation of the beauty of assembly. For more tutorial on assembly and visualization of these information, visit my youtube channel . Okay so lets get started. We will be using Netwide Assembler (NASM) to write our program. The general format of NASM file is this: ;This is a comment SECTION .data ;declare variable here SECTION .bss ;declare actual, dynamic variable SECTION .text ;where your program code/assembly code lives ; Working with Data Section In your .data section, you can declare variables like this: nameOfVariable: db 32 ;this declares a variable names nameOfVariable...

Introduction to Linux Kernel Programming

The Linux kernel is designed as a mixture of a monolithic binary image and a micro-kernel.  This combination allows for the best of both worlds.  On the monolithic side, all the code for the kernel to work with the user and hardware is already installed and ready for fast access, but the downside is that to add more functionality you need to rebuild the entire kernel.   In a different manner, a micro-kernel is composed of small pieces  of code that can be meshed today and more pieces can be added or removed as needed.  However, the downside to micro-kernel is a slower performance. Adding a module to the Kernel Linux is organized as both monolithic, one huge binary, and micro-kernel, as you can add more functionality to it.  The process of adding more functionality to the kernel can be illustrated by the crude image to the left. The process begins by using the command insmod with the name of the kernel module you want (which usually ends with ex...