All Downloads are FREE. Search and download functionalities are using the official Maven repository.

weka.gui.graphvisualizer.DotParser Maven / Gradle / Ivy

Go to download

The Waikato Environment for Knowledge Analysis (WEKA), a machine learning workbench. This is the stable version. Apart from bugfixes, this version does not receive any other updates.

There is a newer version: 3.8.6
Show newest version
/*
 *    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 2 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, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 *    DotParser.java
 *    Copyright (C) 2003 University of Waikato, Hamilton, New Zealand
 *
 */
package weka.gui.graphvisualizer;

import java.io.Reader;
import java.io.StreamTokenizer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.FileWriter;

import weka.core.FastVector;
import weka.gui.graphvisualizer.GraphNode;
import weka.gui.graphvisualizer.GraphEdge;



/**
 * This class parses input in DOT format, and
 * builds the datastructures that are passed to it.
 * It is NOT 100% compatible with the DOT format. The
 * GraphNode and GraphEdge classes do not have any provision
 * for dealing with different colours or  shapes of nodes,
 * there can however, be a different label and ID for a
 * node. It  also does not do anything for labels for
 * edges. However, this class won't crash or throw an
 * exception if it encounters any of the above
 * attributes of an edge or a node. This class however,
 * won't be able to deal with things like subgraphs and
 * grouping of nodes.
 *
 * @author Ashraf M. Kibriya ([email protected])
 * @version $Revision: 7059 $ - 23 Apr 2003 - Initial version (Ashraf M. Kibriya)
 */
public class DotParser implements GraphConstants  {
  
  /** These holds the nodes and edges of the graph */
  protected FastVector m_nodes, m_edges;
  /** This is the input containing DOT stream  to be parsed */
  protected Reader m_input;
  /**  This holds the name of the graph if there is any otherwise it is null */
  protected String m_graphName;
  
  /**
   *
   *  Dot parser Constructor
   *
   * @param input - The input, if passing in a string then
   *                encapsulate that in String reader object
   * @param nodes - Vector to put in GraphNode objects,
   *                corresponding to the nodes parsed in from
   *                the input
   * @param edges - Vector to put in GraphEdge objects,
   *                corresponding to the edges parsed in from
   *                the input
   */
  public DotParser(Reader input, FastVector nodes, FastVector edges) {
    m_nodes = nodes; m_edges = edges;
    m_input = input;
  }
  
  
  /**
   * This method parses the string or the InputStream that we
   * passed in through the constructor and builds up the
   * m_nodes and m_edges vectors
   *
   * @return - returns the name of the graph
   */
  public String parse() {
    StreamTokenizer tk = new StreamTokenizer(new BufferedReader(m_input));
    setSyntax(tk);
    
    graph(tk);
    
    return m_graphName;
  }
  
  
  /**
   * This method sets the syntax of the StreamTokenizer.
   * i.e. set the whitespace, comment and delimit chars.
   *
   */
  protected void setSyntax(StreamTokenizer tk) {
    tk.resetSyntax();
    tk.eolIsSignificant(false);
    tk.slashStarComments(true);
    tk.slashSlashComments(true);
    tk.whitespaceChars(0,' ');
    tk.wordChars(' '+1,'\u00ff');
    tk.ordinaryChar('[');
    tk.ordinaryChar(']');
    tk.ordinaryChar('{');
    tk.ordinaryChar('}');
    tk.ordinaryChar('-');
    tk.ordinaryChar('>');
    tk.ordinaryChar('/');
    tk.ordinaryChar('*');
    tk.quoteChar('"');
    tk.whitespaceChars(';',';');
    tk.ordinaryChar('=');
  }
  
  /*************************************************************
   *
   * Following methods parse the DOT input and mimic the DOT
   * language's grammar in their structure
   *
   *************************************************************
   */
  protected void graph(StreamTokenizer tk) {
    try {
      tk.nextToken();
      
      if(tk.ttype==tk.TT_WORD) {
        if(tk.sval.equalsIgnoreCase("digraph")) {
          tk.nextToken();
          if(tk.ttype==tk.TT_WORD) {
            m_graphName = tk.sval;
            tk.nextToken();
          }
          
          while(tk.ttype!='{') {
            System.err.println(Messages.getInstance().getString("DotParser_Graph_Error_Text_First") + tk.lineno()+Messages.getInstance().getString("DotParser_Graph_Error_Text_Second")+
            tk.sval);
            tk.nextToken();
            if(tk.ttype==tk.TT_EOF)
              return;
          }
          stmtList(tk);
        }
        else if(tk.sval.equalsIgnoreCase("graph"))
          System.err.println(Messages.getInstance().getString("DotParser_Graph_Error_Text_Third"));
        else
          System.err.println(Messages.getInstance().getString("DotParser_Graph_Error_Text_Fourth")+
          tk.lineno());
      }
    }
    catch(Exception ex) { ex.printStackTrace(); }
    
    
    //int tmpMatrix[][] = new int[m_nodes.size()][m_nodes.size()];
    //for(int i=0; i='a' && tk.ttype<='z')
    || (tk.ttype>='A' && tk.ttype<='Z')) {
      if(m_nodes!=null && !(m_nodes.contains( new GraphNode(tk.sval, null))) ) {
        m_nodes.addElement( new GraphNode(tk.sval, tk.sval) );
        //System.out.println("Added node >"+tk.sval+"<");
      }
    }
    else
    { throw new Exception(); }
    
    //tk.nextToken();
  }
  
  
  protected void nodeStmt(StreamTokenizer tk, final int nindex)
  throws Exception {
    tk.nextToken();
    
    GraphNode temp = (GraphNode) m_nodes.elementAt(nindex);
    
    if(tk.ttype==']' || tk.ttype==tk.TT_EOF)
      return;
    else if(tk.ttype==tk.TT_WORD) {
      
      if(tk.sval.equalsIgnoreCase("label")) {
        
        tk.nextToken();
        if(tk.ttype=='=') {
          tk.nextToken();
          if(tk.ttype==tk.TT_WORD || tk.ttype=='"')
            temp.lbl = tk.sval;
          else {
            System.err.println(Messages.getInstance().getString("DotParser_NodeStmt_Error_Text_First") + tk.lineno());
            tk.pushBack();
          }
        }
        else {
          System.err.println(Messages.getInstance().getString("DotParser_NodeStmt_Error_Text_Second") + tk.lineno());
          tk.pushBack();
        }
      }
      
      else if(tk.sval.equalsIgnoreCase("color")){
        
        tk.nextToken();
        if(tk.ttype=='=') {
          tk.nextToken();
          if(tk.ttype==tk.TT_WORD || tk.ttype=='"')
            ;
          else {
            System.err.println(Messages.getInstance().getString("DotParser_NodeStmt_Error_Text_Third") + tk.lineno());
            tk.pushBack();
          }
        }
        else {
          System.err.println(Messages.getInstance().getString("DotParser_NodeStmt_Error_Text_Fourth") + tk.lineno());
          tk.pushBack();
        }
      }
      
      else if(tk.sval.equalsIgnoreCase("style")) {
        
        tk.nextToken();
        if(tk.ttype=='=') {
          tk.nextToken();
          if(tk.ttype==tk.TT_WORD || tk.ttype=='"')
            ;
          else {
            System.err.println(Messages.getInstance().getString("DotParser_NodeStmt_Error_Text_Fifth") + tk.lineno());
            tk.pushBack();
          }
        }
        else {
          System.err.println(Messages.getInstance().getString("DotParser_NodeStmt_Error_Text_Sixth") + tk.lineno());
          tk.pushBack();
        }
      }
    }
    nodeStmt(tk, nindex);
  }
  
  
  protected void edgeStmt(StreamTokenizer tk, final int nindex)
  throws Exception {
    tk.nextToken();
    
    GraphEdge e=null;
    if(tk.ttype=='>') {
      tk.nextToken();
      if(tk.ttype=='{') {
        while(true) {
          tk.nextToken();
          if(tk.ttype=='}')
            break;
          else {
            nodeID(tk);
            e = new GraphEdge(nindex,
            m_nodes.indexOf( new GraphNode(tk.sval, null) ),
            DIRECTED);
            if( m_edges!=null && !(m_edges.contains(e)) ) {
              m_edges.addElement( e );
              //System.out.println("Added edge from "+
              //                  ((GraphNode)(m_nodes.elementAt(nindex))).ID+
              //                  " to "+
              //	        ((GraphNode)(m_nodes.elementAt(e.dest))).ID);
            }
          }
        }
      }
      else {
        nodeID(tk);
        e = new GraphEdge(nindex,
        m_nodes.indexOf( new GraphNode(tk.sval, null) ),
        DIRECTED);
        if( m_edges!=null && !(m_edges.contains(e)) ) {
          m_edges.addElement( e );
          //System.out.println("Added edge from "+
          //                 ((GraphNode)(m_nodes.elementAt(nindex))).ID+" to "+
          //		     ((GraphNode)(m_nodes.elementAt(e.dest))).ID);
        }
      }
    }
    else if(tk.ttype=='-') {
      System.err.println(Messages.getInstance().getString("DotParser_EdgeStmt_Error_Text_First") + tk.lineno()+
    		  Messages.getInstance().getString("DotParser_EdgeStmt_Error_Text_Second"));
      if(tk.ttype==tk.TT_WORD)
        tk.pushBack();
      return;
    }
    else {
      System.err.println(Messages.getInstance().getString("DotParser_EdgeStmt_Error_Text_Third") + tk.lineno()+Messages.getInstance().getString("DotParser_EdgeStmt_Error_Text_Fourth"));
      if(tk.ttype==tk.TT_WORD)
        tk.pushBack();
      return;
    }
    
    tk.nextToken();
    
    if(tk.ttype=='[')
      edgeAttrib(tk, e);
    else
      tk.pushBack();
  }
  
  
  protected void edgeAttrib(StreamTokenizer tk, final GraphEdge e)
  throws Exception {
    tk.nextToken();
    
    if(tk.ttype==']' || tk.ttype==tk.TT_EOF)
      return;
    else if(tk.ttype==tk.TT_WORD) {
      
      if(tk.sval.equalsIgnoreCase("label")) {
        
        tk.nextToken();
        if(tk.ttype=='=') {
          tk.nextToken();
          if(tk.ttype==tk.TT_WORD || tk.ttype=='"')
            System.err.println(Messages.getInstance().getString("DotParser_EdgeAttrib_Text") + tk.sval);//e.lbl = tk.sval;
          else {
            System.err.println(Messages.getInstance().getString("DotParser_EdgeAttrib_Error_Text") + tk.lineno());
            tk.pushBack();
          }
        }
        else {
          System.err.println(Messages.getInstance().getString("DotParser_EdgeAttrib_Error_Text_First") + tk.lineno());
          tk.pushBack();
        }
      }
      else if(tk.sval.equalsIgnoreCase("color")) {
        
        tk.nextToken();
        if(tk.ttype=='=') {
          tk.nextToken();
          if(tk.ttype==tk.TT_WORD || tk.ttype=='"')
            ;
          else {
            System.err.println(Messages.getInstance().getString("DotParser_EdgeAttrib_Error_Text_Second") + tk.lineno());
            tk.pushBack();
          }
        }
        else {
          System.err.println(Messages.getInstance().getString("DotParser_EdgeAttrib_Error_Text_Third") + tk.lineno());
          tk.pushBack();
        }
      }
      
      else if(tk.sval.equalsIgnoreCase("style")) {
        
        tk.nextToken();
        if(tk.ttype=='=') {
          tk.nextToken();
          if(tk.ttype==tk.TT_WORD || tk.ttype=='"')
            ;
          else {
            System.err.println(Messages.getInstance().getString("DotParser_EdgeAttrib_Error_Text_Fourth") + tk.lineno());
            tk.pushBack();
          }
        }
        else {
          System.err.println(Messages.getInstance().getString("DotParser_EdgeAttrib_Error_Text_Fifth") + tk.lineno());
          tk.pushBack();
        }
      }
    }
    edgeAttrib(tk, e);
  }
  
  
  /**
   *
   * This method saves a graph in a file in DOT format.
   * However, if reloaded in GraphVisualizer we would need
   * to layout the graph again.
   *
   * @param filename  - The name of the file to write in. (will overwrite)
   * @param graphName - The name of the graph
   * @param nodes     - Vector containing all the nodes
   * @param edges     - Vector containing all the edges
   */
  public static void writeDOT(String filename, String graphName,
  FastVector nodes, FastVector edges) {
    try {
      FileWriter os = new FileWriter(filename);
      os.write("digraph ", 0, ("digraph ").length());
      if(graphName!=null)
        os.write(graphName+" ", 0, graphName.length()+1);
      os.write("{\n", 0, ("{\n").length());
      
      GraphEdge e;
      for(int i=0; i", 0, ("->").length() );
        os.write(((GraphNode)nodes.elementAt(e.dest)).ID+"\n",
        0,
        ((GraphNode)nodes.elementAt(e.dest)).ID.length()+1);
      }
      os.write("}\n", 0, ("}\n").length());
      os.close();
    }
    catch(IOException ex) { ex.printStackTrace(); }
  }
  
} // DotParser




© 2015 - 2025 Weber Informatics LLC | Privacy Policy