Package hr.fer.zemris.java.custom.scripting.parser

Source Code of hr.fer.zemris.java.custom.scripting.parser.SmartScriptParser

package hr.fer.zemris.java.custom.scripting.parser;

import hr.fer.zemris.java.custom.collections.*;
import hr.fer.zemris.java.custom.scripting.nodes.*;
import hr.fer.zemris.java.custom.scripting.tokens.Token;
import hr.fer.zemris.java.custom.scripting.tokens.TokenConstantDouble;
import hr.fer.zemris.java.custom.scripting.tokens.TokenConstantInteger;
import hr.fer.zemris.java.custom.scripting.tokens.TokenFunction;
import hr.fer.zemris.java.custom.scripting.tokens.TokenOperator;
import hr.fer.zemris.java.custom.scripting.tokens.TokenString;
import hr.fer.zemris.java.custom.scripting.tokens.TokenVariable;

/**
* A parser for a document which generates a tree structure of the document text
* @author Dario Miličić
* @version 1.0
*/

public class SmartScriptParser {

  public String[] tokensFOR = new String[4];
  public String[] tokensEQU;
  private ObjectStack docStack;
 
  /**
   * Default parser constructor which accepts a text document.
   * @param docBody Text document to be parsed.
   * @throws SmartScriptParserException
   */
 
  public SmartScriptParser(String docBody) throws SmartScriptParserException {
    textParser(docBody);
  }
 
  /**
   * Checks if the token is valid
   * @param str A string to be checked.
   * @param TOKEN Token identifier.
   * @return Returns true if the token is valid, else returns false.
   */
 
  private boolean isValidToken(String str, int TOKEN) {
   
    /* TOKEN:
     * 0 - variable
     * 1 - expression
     * 2 - function
     * 3 - symbol (*,+,/,-)
     * 4 - string
     */
     
    switch (TOKEN) {
   
    case 0: // checks variable token
      if( !Character.isLetter(str.charAt(0)) || str.charAt(0) == '@' || str.charAt(0) == '"' )
        return false;
      for(int i = 1; i < str.length(); i++)
        if( !Character.isLetter(str.charAt(i)) && !Character.isDigit(str.charAt(i)) && str.charAt(i) != '_' )
          return false;
      return true;
    case 1: // checks expression token
     
      int signed = 0;
      int decimal = 0;
     
      for(int i = 0; i < str.length(); i++) {
        if(str.charAt(i) == '-' && i == 0 ) signed++;
        else if(str.charAt(i) == '.' && str.length() > 1) decimal++;
        else if(!Character.isDigit(str.charAt(i))) return false;
      }
     
      if( signed <= 1 && decimal <= 1 )
        return true;
    case 2: // checks function token
      if( str.charAt(0) != '@' || !Character.isLetter(str.charAt(1)) )
        return false;
      for(int i = 2; i < str.length(); i++)
        if( !Character.isLetter(str.charAt(i)) && !Character.isDigit(str.charAt(i)) && str.charAt(i) != '_' )
          return false;
      return true;
    case 3: // checks symbol token
      char symbol = str.charAt(0);
      if( symbol == '*' || symbol == '+' || symbol == '/' || symbol == '-' )
        return true;
      return false;

    }
   
    return false;
  }
 
  /**
   * Collects all the expressions in a FOR tag and puts it in a string array.
   * @param str FOR tag in a string format.
   * @param idx Index of a starting element of the FOR tag (whitespace after '$').
   * @return Returns the index increased by the size of the FOR loop
   */
 
  private int getFOR(String str, int idx) {

    String[] tokens = new String[4];
    char c;
   
    int i = 0;
   
    StringBuilder buffer = new StringBuilder();
   
    while ( str.charAt(idx) != '$' ) {
     
      c = str.charAt(idx);
     
      if( str.charAt(idx + 1) == '$' && c != ' ' )
        buffer.append(c);
     
      if ( (str.charAt(idx + 1) == '$' || c == ' ') && buffer.length() > 0 )  {
       
        if( isValidToken(buffer.toString(), 0) ||
          isValidToken(buffer.toString(), 1)) { 
         
          if( i > 4 ) throw new SmartScriptParserException();
          tokens[i++] = buffer.toString();
          buffer = new StringBuilder();
        } else throw new SmartScriptParserException();
      } else if(c != ' ')
        buffer.append(c);
     
      idx++;
    }

    for(i = 0; i < tokens.length; i++)
      tokensFOR[i] = tokens[i];   
   
    return idx - 1;
  }
 
  /**
   * Collects all the expressions in a = tag and puts it in a string array.
   * @param str = tag in a string format.
   * @param idx Index of a starting element of the = tag (whitespace after '$').
   * @return Returns the index increased by the size of the EQU tag
   */
 
  private int getEQU(String str, int idx) {
   
    char c;
    StringBuilder buffer = new StringBuilder();
    ArrayBackedIndexedCollection array = new ArrayBackedIndexedCollection();
    boolean exit = false;
   
    final int ESC_T = 0;
    final int ESC_S = 1;
    final int TOKENS = 2;
    final int STRING = 3;
    final int EXIT = 4;
    int state = TOKENS;

    while(!exit && idx < str.length()) {
     
      c = str.charAt(idx);
     
      switch (state) {
      case TOKENS:
        switch (c) {
        case '$':
          if(buffer.length() > 0) {
            array.add((String)buffer.toString());
            buffer = new StringBuilder();
          }
          state = EXIT;
          break;
        case '"':
          state = STRING;
          buffer.append(c);
          break;
        case ' ':
          if( buffer.length() > 0 ) {
            array.add((String)buffer.toString());
            buffer = new StringBuilder();
          }
          break;
        case '\\':
          state = ESC_T;
          break;
        case '\r':
          if( buffer.length() > 0 ) {
            array.add((String)buffer.toString());
            buffer = new StringBuilder();
          }
          break;
        case '\n':
          if( buffer.length() > 0 ) {
            array.add((String)buffer.toString());
            buffer = new StringBuilder();
          }
          break;
        default:
          buffer.append(c);
          break;
        }
        idx++;
        break;
      case STRING:
        switch (c) {
        case '"':
          state = TOKENS;
          buffer.append(c);
          break;
        case '\\':
          state = ESC_S;
          break;
        default:
          buffer.append(c);
          break;
        }
        idx++;
        break;
      case ESC_S:
        buffer.append("\\" + c);
        state = STRING;
        idx++;
        break;
      case ESC_T:
        buffer.append("\\" + c);
        state = TOKENS;
        idx++;
        break;
      case EXIT:
        exit = true;
        break;
      }
    }
   
    tokensEQU = new String[array.size()];
    for (int i = 0; i < array.size(); i++) {
      tokensEQU[i] = array.get(i).toString();
    }
   
    return idx - 2;
  }
 
  /**
   * Parses a document text and forms a tree structure using a stack.
   * @param str Document text to be parsed.
   */
 
  private void textParser(String str) {
 
    docStack = new ObjectStack();
    docStack.push(new DocumentNode());
   
    char c;
    StringBuilder buffer = new StringBuilder();
   
    final int ESC = 1;
    final int TEXT = 2;
    final int TAG_OPEN = 3;
    final int TAG_CLOSE = 4;
    final int TAG = 5;
    int state = TEXT;
    int i = 0;
   
    while ( i < str.length() ) {

      c = str.charAt(i);
     
      switch (state) {
     
      case TEXT:
             
        if (c == '\\') {
          state = ESC;
        } else if (c == '[') {
          state = TAG_OPEN;
         
          Node parentNode = (Node) docStack.peek();
         
          if( buffer.length() > 0 ) {
            TextNode textNode = new TextNode(buffer.toString());
            parentNode.addChildNode(textNode);
            buffer = new StringBuilder();
          }
        } else {
          buffer.append(c);
        }
        break;
       
      case ESC:
        if(c == '[' || c == 'n' || c == 't' || c == 'r')
          buffer.append('\\').append(c);
        else throw new SmartScriptParserException();
        state = TEXT;
        break;
       
      case TAG_OPEN:
        if(c != '$') throw new SmartScriptParserException();
        if(str.charAt(i+1) == ' ')
          i++;
        state = TAG;
        break;
       
      case TAG:
        if( c == '=' ) {
          i = getEQU(str, i + 1);
         
          Node parentNode = (Node) docStack.peek();
         
          Token[] echoTokens = new Token[tokensEQU.length];
          for(int j = 0; j < tokensEQU.length; j++)
            echoTokens[j] = tokenConvert(tokensEQU[j]);
         
          EchoNode equNode = new EchoNode(echoTokens);
         
          parentNode.addChildNode(equNode);
        } else if(c == ' '  && buffer.length() > 0) {
         
          if(buffer.toString().equals("FOR")) { // push FOR to stack
            i = getFOR(str, i);
           
            Node parentNode = (Node) docStack.peek();
            ForLoopNode forNode = new ForLoopNode((TokenVariable)tokenConvert(tokensFOR[0]), tokenConvert(tokensFOR[1]), tokenConvert(tokensFOR[2]), tokenConvert(tokensFOR[3]));
           
            parentNode.addChildNode(forNode);
            docStack.push(forNode);
          }
          else if(buffer.toString().equals("=")) {
           
            i = getEQU(str, i);
           
            Node parentNode = (Node) docStack.peek();
           
            Token[] echoTokens = new Token[tokensEQU.length];
            for(int j = 0; j < tokensEQU.length; j++)
              echoTokens[j] = tokenConvert(tokensEQU[j]);
           
            EchoNode equNode = new EchoNode(echoTokens);
           
            parentNode.addChildNode(equNode);
          }
        }
        else if(c == '$') {
          state = TAG_CLOSE;
          if(buffer.toString().equals("END"))
            docStack.pop(); // pop stack
        }
        else if(c != ' ')
          buffer.append(c);
        break;
       
      case TAG_CLOSE:
       
        if(c != ']') throw new SmartScriptParserException();
        buffer = new StringBuilder();
        state = TEXT;
        break;
       
      default:
        break;
      }
      i++;
    }
  }
 
  /**
   * Looks for the item documentNode on the stack.
   * @return Returns a documentNode if the stack is not empty.
   */
 
  public DocumentNode getDocumentNode() {
    DocumentNode docNode = null;
    try {
      docNode = (DocumentNode) docStack.peek();
    } catch (ClassCastException e) {
      throw new SmartScriptParserException("Syntax error!");
    }
    return docNode;
  }
 
  /**
   * Converts strings to tokens.
   * @param token String token to convert.
   * @return Returned token.
   */
 
  private Token tokenConvert(String token) {
   
    Token tmp;
   
    if (token == null) return null;
   
    try{
      int argInt = Integer.parseInt(token);
      tmp = new TokenConstantInteger(argInt);
    }
    catch (NumberFormatException nFE0) {
       
      try {
        double argDouble = Double.parseDouble(token);
        tmp = new TokenConstantDouble(argDouble);
         
      } catch (NumberFormatException nFE1) {
         
        char c = token.charAt(0);
         
        if(c == '@') {
          if( !isValidToken(token, 2) ) throw new SmartScriptParserException();
          tmp = new TokenFunction(token);
        }
        else if(c == '*' || c == '/' || c == '+' || c == '-') {
          if( !isValidToken(token, 3) ) throw new SmartScriptParserException();
          tmp = new TokenOperator(token);
        }
        else if(c == '\"') {
          tmp = new TokenString(token.substring(1, token.length()-1));
        }
        else {
          if( !isValidToken(token, 0) ) throw new SmartScriptParserException();
          tmp = new TokenVariable(token);
        }
      }
    }
   
    return tmp;
  }
}
TOP

Related Classes of hr.fer.zemris.java.custom.scripting.parser.SmartScriptParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.