package graph; import java.awt.*; import java.util.*; import java.lang.*; import java.io.StreamTokenizer; import java.io.InputStream; import java.io.IOException; import java.net.URL; import java.applet.Applet; /* ************************************************************************** ** ** Class BuildGraph ** ************************************************************************** ** Copyright (C) 1996 Leigh Brookshaw ** ** 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. ************************************************************************** ** ** This class will parse a description file and build the ** plot based on the instructions in the file ** *************************************************************************/ /** * This class will parse a description file and build a * plot based on the instructions in the file. * The build Graph class, with attached Axes and DataSets can be accessed * though methods in the class * * @version $Revision: 1.14 $, $Date: 1996/09/06 00:08:49 $ * @author Leigh Brookshaw */ public class BuildGraph extends ScanWord { /* ********************** ** Constants *********************/ /* ** Specifiy the integer values associated with keywords. Every integer ** in this list is associated with keyword used in the input file */ static final int BEGIN = 256; static final int GRAPH2D = 257; static final int MARKER = 258; static final int AXIS = 259; static final int URL = 260; static final int DATA = 261; static final int SIZE = 262; static final int COLOR = 263; static final int NAME = 264; static final int TITLE = 265; static final int LABEL = 266; static final int FONT = 267; static final int STYLE = 268; static final int BOTTOM = 269; static final int TOP = 270; static final int LEFT = 271; static final int RIGHT = 272; static final int END = 273; static final int G2DINT = 274; static final int OFF = 275; static final int ON = 276; static final int ATTACH = 277; static final int PLAIN = 278; static final int BOLD = 279; static final int ITALIC = 280; static final int DEBUG = 281; static final int GRID = 282; static final int ZERO = 283; static final int CONTOUR = 284; static final int LLEVELS = 285; static final int NUMBER = 286; static final int CDATA = 287; static final int FUNCTION = 288; static final int XRANGE = 289; static final int YRANGE = 290; static final int BACKGROUND = 291; static final int LOGCONTOURS = 292; static final int CLABELS = 293; static final int SQUARE = 294; /* ** Specify Internal interger values. These constants are associated ** with objects nolonger in the context of the input file. But have ** been constructed by the program from a number of keyword commands. */ static final int MARKER_STYLE = 512; static final int MARKER_COLOR = 513; static final int MARKER_SIZE = 514; static final int LABEL_COLOR = 515; static final int LABEL_FONT = 517; static final int GRID_COLOR = 520; static final int GRID_OFF = 521; static final int ZERO_COLOR = 522; static final int ZERO_OFF = 523; static final int MARKER_URL = 524; static final int GRID_ON = 525; static final int ZERO_ON = 526; static final int XMIN = 527; static final int XMAX = 528; static final int YMIN = 529; static final int YMAX = 530; static final int XNUMBER = 531; static final int YNUMBER = 532; static final int LABEL_OFF = 533; /** * The BUILD stack. Everything pushed on this stack has to be * built from other objects. An example would be a Font, which * is constructed from Logical name, style and size. */ protected Stack build = new Stack(); /** * The Object stack. All input tokens get pushed onto and * popped off this stack. */ protected Stack object = new Stack(); /** * The class vector. This contains final class objects that cannot be * deleted. That is * we don't want these classes unnattached and collected into the garbage. * The obvious classes here are the main Graph2D class, the Axes of the plot * DataSets etc. */ protected Vector built = new Vector(); /** * The constructed Graph Object */ protected Object graph = null; /** * The TextLine containing the title */ protected TextLine graphtitle = null; /** * The Calling Applet */ protected Applet applet; /** * Debug. If true output copious debug messages. Though unless you know * what is going on with the code most messages will probably be * meaningless */ protected boolean debug = false; /* ** This vector contains all the datasets as they are built. ** the data sets in this lists are then searched so that they can ** be attached to axis. */ private Vector datasets = new Vector(); /* ********************* ** Public Variables ********************/ /** * Current line being parsed */ public int lineno = 1; /** * The current brace level. At the end of the input if all * braces are matched the level should be back to zero. */ public int level = 0; /* ********************* ** Constructors *******************/ /** * Instantiate the class * @param in The inputstream to be read * @param ap the driving applet. */ public BuildGraph( InputStream in, Applet ap ) { super(in); applet = ap; /* ** Specifiy The Key Words and associate them with the integer Values */ addKeyWord("{", BEGIN); addKeyWord("}", END); addKeyWord("graph2d", GRAPH2D); addKeyWord("g2dint", G2DINT); addKeyWord("marker", MARKER); addKeyWord("axis", AXIS); addKeyWord("url", URL); addKeyWord("data", DATA); addKeyWord("size", SIZE); addKeyWord("color", COLOR); addKeyWord("name", NAME); addKeyWord("title", TITLE); addKeyWord("label", LABEL); addKeyWord("font", FONT); addKeyWord("style", STYLE); addKeyWord("bottom", BOTTOM); addKeyWord("top", TOP); addKeyWord("left", LEFT); addKeyWord("right", RIGHT); addKeyWord("on", ON); addKeyWord("off", OFF); addKeyWord("attach", ATTACH); addKeyWord("plain", PLAIN); addKeyWord("bold", BOLD); addKeyWord("italic", ITALIC); addKeyWord("debug", DEBUG); addKeyWord("grid", GRID); addKeyWord("zero", ZERO); addKeyWord("contour", CONTOUR); addKeyWord("number", NUMBER); addKeyWord("cdata", CDATA); addKeyWord("function", FUNCTION); addKeyWord("xrange", XRANGE); addKeyWord("yrange", YRANGE); addKeyWord("background", BACKGROUND); addKeyWord("llevels", LLEVELS); addKeyWord("square", SQUARE); addKeyWord("log", LOGCONTOURS); } /******************** ** ** Public Methods ** ********************/ /** * Get the Graph object that has been built! */ public Object getGraph() { return graph; } /** * Get the title of the Graph */ public TextLine getGraphTitle() { return graphtitle; } /** * Get a vector of all the built Classes. * Ie the DataSets, Axis, Graph etc. * This can be used by an applet to override anything specified in the * input file */ public Vector getBuilt() { return built; } /** * This is THE method that parses the input file and constructs the plot. */ public void parse() { int token; Object o; NamedObject nobj; boolean cont = true; while( cont ) { /* ** Grab a word from the stream and Do something with it! */ token = nextWord(); debugMessage("Main",token); switch (token) { /* ** Turn on the debug messages. */ case DEBUG: debug = !debug; break; /* ** Instantiate the Graph class and push it onto ** the object stack! */ case CONTOUR: if(graph != null) { errorAtLine("Graph already defined."); return; } graph = new Contour(); nobj = new NamedObject(graph, CONTOUR); object.push(nobj); break; case G2DINT: if(graph != null) { errorAtLine("Graph already defined."); return; } graph = new G2Dint(); nobj = new NamedObject(graph, G2DINT); object.push(nobj); break; case GRAPH2D: if(graph != null) { errorAtLine("Graph already defined."); return; } graph = new Graph2D(); nobj = new NamedObject(graph, GRAPH2D); object.push(nobj); break; /* ** End of the file. Exit the loop */ case TT_EOF: cont = false; break; /* ** End of Line - Increment the line counter */ case TT_EOL: lineno++; if( lineno == (lineno/10)*10 ) { applet.showStatus("Reading input: Line "+lineno); } break; /* ** LEFT, RIGHT, BOTTOM and TOP perform different tasks based on Context. ** Inside an AXIS group they position the axis and are standalone keywords ** Inside a GRAPH context they are followed by an integer and are the ** border widths in pixels. */ case LEFT: case RIGHT: case TOP: case BOTTOM: if( isContext(AXIS) ) { nobj = new NamedObject(token); } else { int toke = nextWord(); if( toke == TT_NUMBER ) { nobj = new NamedObject( new Integer((int)(nval+0.01)), token); } else { errorAtLine( "In this context LEFT, RIGHT, TOP or BOTTOM should be followed an integer"); return; } } object.push(nobj); break; /* ** Build a URL object and push it onto the object stack ** The URL keyword MUST be followed by a string */ case URL: token = nextWord(); if( token == STRING ) { try { URL url = new URL(applet.getDocumentBase(),sval); nobj = new NamedObject(url,URL); } catch(Exception e) { errorAtLine("Failed to build URL!"); return; } } else { errorAtLine("URL should be followed by a string"); return; } object.push(nobj); break; /* ** The ATTACH keyword is followed by the name of the ** DataSet to be attached. Attach only appears ** inside an AXIS group. */ case ATTACH: if( !isContext(AXIS) ) { errorAtLine("ATTACH should only appear in AXIS context"); return; } token = nextWord(); if( token == STRING ) { nobj = new NamedObject(sval,ATTACH); } else { errorAtLine("ATTACH should be followed by a string"); return; } object.push(nobj); break; /* ** Marker style, or font style depending on context */ case STYLE: if( !isContext(MARKER) && !isContext(FONT)) { errorAtLine( "STYLE should only appear in MARKER or FONT context"); return; } token = nextWord(); if( token == PLAIN ) { nobj = new NamedObject(PLAIN); } else if( token == BOLD ) { nobj = new NamedObject(BOLD); } else if( token == ITALIC ) { nobj = new NamedObject(PLAIN); } else if( token == TT_NUMBER ) { nobj = new NamedObject(new Integer((int)(nval+0.01)), STYLE); } else { errorAtLine( "STYLE should be followed an integer or Keyword"); return; } object.push(nobj); break; /* ** Size of font or marker. Size should be followed by an integer */ case SIZE: if( !isContext(MARKER) && !isContext(FONT)) { errorAtLine( "SIZE should only appear in MARKER or FONT context"); return; } token = nextWord(); if( token == TT_NUMBER ) { nobj = new NamedObject(new Integer((int)(nval+0.01)), SIZE); } else { errorAtLine("SIZE should be followed by an integer"); return; } object.push(nobj); break; /* ** Which contour levels are to get labels. */ case LLEVELS: if( !isContext(CONTOUR)) { errorAtLine( "LLEVELS should only appear in CONTOUR context"); return; } token = nextWord(); if( token == TT_NUMBER ) { nobj = new NamedObject(new Integer((int)(nval+0.01)), LLEVELS); } else { errorAtLine("LLEVELS should be followed by an integer"); return; } object.push(nobj); break; /* ** Parse a color. Color should be followed by 3 integers in ** the range 0-255 */ case COLOR: case BACKGROUND: int i; int rgb[]={-1,-1,-1}; for(i=0; i<3; i++) { int t = nextWord(); if(t != TT_NUMBER || nval <0 || nval > 255) { errorAtLine("Incorrect Color definition"); return; } rgb[i] = (int)(nval+0.001); } if(token == COLOR) { nobj = new NamedObject(new Color(rgb[0], rgb[1], rgb[2]), COLOR); object.push(nobj); } else { if( isContext(DATA) || isContext(CDATA) ) { ((Graph2D)graph).setDataBackground( new Color(rgb[0], rgb[1], rgb[2]) ); } else { ((Graph2D)graph).setGraphBackground( new Color(rgb[0], rgb[1], rgb[2]) ); } } break; /* ** Name the current context or the string to be used as a label ** or title. Name should be followed by a string */ case NAME: token = nextWord(); if( token == STRING ) { nobj = new NamedObject(sval,NAME); } else { errorAtLine("NAME should be followed by a string"); return; } object.push(nobj); break; case FUNCTION: token = nextWord(); if( token == STRING ) { nobj = new NamedObject(sval,FUNCTION); } else { errorAtLine("FUNCTION should be followed by a string"); return; } object.push(nobj); break; case NUMBER: token = nextWord(); if( token == TT_NUMBER ) { nobj = new NamedObject( new Integer((int)(nval+0.01)), NUMBER); } else { errorAtLine("NUMBER should be followed by an integer"); return; } object.push(nobj); break; case XRANGE: case YRANGE: boolean error = false; double min = 0.0; double max = 0.0; int num = 0; int t = nextWord(); if( t == TT_NUMBER ) { num = (int)(nval+0.001); t = nextWord(); if( t == TT_NUMBER ) { min = nval; t = nextWord(); if( t == TT_NUMBER ) { max = nval; } else { error = true; } } else { error = true; } } else { error = true; } if(error) { errorAtLine( "Range limits must be followed by 3 numbers"); return; } if(min == max) { errorAtLine( "Range limits must not be the same"); return; } if(num <= 1) { errorAtLine( "Number of points must be greater than 1"); return; } if(min > max ) { double tmp = max; max = min; min = tmp; } if(token == XRANGE) { nobj = new NamedObject(new Integer(num),XNUMBER); object.push(nobj); nobj = new NamedObject(new Double(min),XMIN); object.push(nobj); nobj = new NamedObject(new Double(max),XMAX); object.push(nobj); } else { nobj = new NamedObject(new Integer(num),YNUMBER); object.push(nobj); nobj = new NamedObject(new Double(min),YMIN); object.push(nobj); nobj = new NamedObject(new Double(max),YMAX); object.push(nobj); } break; /* ** unknown keyword! */ case UNKNOWN: errorAtLine("Unknown keyword!!"); break; /* ** begin a new group or context. The object to be built ** should be the last thing pushed onto the object stack. ** Move it to the build stack and push BEGIN onto the object ** stack to act as a delimiter on the stack */ case BEGIN: level++; build.push(object.pop()); object.push(new NamedObject(BEGIN)); break; /* ** End of a group or context. Everything on the object stack ** down to the BEGIN object relate to the current build object ** Build the object and push this built object onto the ** object stack. */ case END: level--; build((NamedObject)(build.pop())); break; /* ** Whatever it is push it onto the object stack. */ default: object.push(new NamedObject(token)); break; } } /* ** Finished - lets see if anything major was not defined */ closeStream(); if(graph == null) { System.out.println("Graph never defined! Cannot build graph!"); return; } if(level != 0 ) { System.out.println("Mismatched Braces!! Will try and build graph."); } /* ** Errors could have occured - but lets try and repaint and keep going */ if( graph instanceof Graph2D ) { ((Graph2D)graph).repaint(); } else if( graph instanceof G2Dint ) { ((G2Dint)graph).repaint(); } else if( graph instanceof Contour ) { ((Contour)graph).repaint(); } else { System.out.println("Unknown graph type - totally confused!"); } } /* ********************* ** ** Protected Methods ** *********************/ /** * Check if the object is on the "to be built" stack. This way context can be * checked so potential errors flagged. * @param token is this the object we are currently building? * @return true if the token matches current object being built */ protected boolean isContext(int token) { int i; for(i=0; itrue if the build was successful. */ protected boolean build(NamedObject nobj) { switch(nobj.id) { case FONT: return buildFont(); case MARKER: return buildMarker(); case TITLE: return buildTitle(); case LABEL: return buildLabel(); case DATA: case CDATA: return buildData(nobj.id); case AXIS: return buildAxis(); case GRID: return buildGrid(); case ZERO: return buildZero(); case G2DINT: case GRAPH2D: case CONTOUR: return buildGraph(nobj.id); default: errorAtLine("Incorrect keyword followed by braces"); return false; } } /** * Pop things off the object stack and build the graph * @param type Type of graph to build, Graph2D, G2Dint, Contour. * @return true if the build was successful */ protected boolean buildGraph(int type) { NamedObject nobj; Axis axis; String dname; if(type==CONTOUR) dname = "Contour"; else if(type==G2DINT) dname = "G2Dint"; else dname = "Graph"; while( true ) { nobj = (NamedObject)(object.pop()); debugMessage(dname,nobj.id); switch (nobj.id) { case AXIS: axis = (Axis)(nobj.getObject()); if(type == GRAPH2D) { ((Graph2D)graph).attachAxis(axis); } else { ((G2Dint)graph).attachAxis(axis); } break; case DATA: ((Graph2D)graph).attachDataSet( (DataSet)(nobj.getObject())); break; case ATTACH: axis = (Axis)(nobj.getObject()); String name = nobj.getName(); boolean attach = false; for(int i=0; itrue if the build was successful */ protected boolean buildContour(NamedObject nobj) { switch (nobj.id) { case NUMBER: ((Contour)graph).setNLevels( ((Integer)(nobj.getObject())).intValue() ); break; case LLEVELS: ((Contour)graph).setLabelLevels( ((Integer)(nobj.getObject())).intValue() ); break; case COLOR: ((Contour)graph).setContourColor( (Color)(nobj.getObject())); break; case LOGCONTOURS: ((Contour)graph).logLevels = true; break; default: return false; } return true; } /** * @return true if the build was successful */ protected boolean buildFont() { String name = "TimesRoman"; int style = Font.PLAIN; int size = 20; NamedObject nobj; Font f; while( true ) { nobj = (NamedObject)(object.pop()); debugMessage("Font",nobj.id); switch (nobj.id) { case NAME: name = (String)(nobj.getObject()); break; case SIZE: size = ((Integer)(nobj.getObject())).intValue(); break; case PLAIN: style += Font.PLAIN; break; case BOLD: style += Font.BOLD; break; case ITALIC: style += Font.ITALIC; break; case BEGIN: try { f = new Font(name,style,size); nobj = new NamedObject(f,FONT); object.push(nobj); applet.showStatus("BuildGraph: Built Font!"); return true; } catch(Exception e) { errorAtLine("Ill formed font specification"); return false; } default: errorAtLine("Incorrect keyword in Font specification"); return false; } } } /** * @return true if the build was successful */ protected boolean buildTitle() { NamedObject nobj; TextLine title = new RTextLine(); while( true ) { nobj = (NamedObject)(object.pop()); debugMessage("Title",nobj.id); switch (nobj.id) { case NAME: title.setText((String)(nobj.getObject())); break; case FONT: title.setFont((Font)(nobj.getObject())); break; case COLOR: title.setColor((Color)(nobj.getObject())); break; case BEGIN: nobj = new NamedObject(title,TITLE); object.push(nobj); applet.showStatus("BuildGraph: Built Title!"); return true; default: errorAtLine("Incorrect keyword in Title specification"); return false; } } } /** * @return true if the build was successful */ protected boolean buildLabel() { NamedObject nobj; NamedObject color = null; NamedObject font = null; while( true ) { nobj = (NamedObject)(object.pop()); debugMessage("Label",nobj.id); switch (nobj.id) { case FONT: font = nobj; font.setId(LABEL_FONT); break; case COLOR: color = nobj; color.setId(LABEL_COLOR); break; case BEGIN: if(color != null) object.push(color); if(font != null) object.push(font); applet.showStatus("BuildGraph: Built Axis Label!"); return true; default: errorAtLine("Incorrect keyword in Label specification"); return false; } } } /* * @return true if the build was successful */ protected boolean buildMarker() { NamedObject nobj; Markers m = null; NamedObject size = null; NamedObject color = null; NamedObject style = null; while( true ) { nobj = (NamedObject)(object.pop()); debugMessage("Marker",nobj.id); switch (nobj.id) { case SIZE: size = nobj; size.setId(MARKER_SIZE); break; case COLOR: color = nobj; color.setId(MARKER_COLOR); break; case STYLE: style = nobj; if( style.getObject() instanceof Integer) { style.setId(MARKER_STYLE); } else { errorAtLine("Style should be an Integer in MARKER"); return false; } break; case URL: try { m = new Markers( (URL)nobj.getObject() ); } catch(Exception e) { errorAtLine("Failed to load markers: "+ e.getMessage()); } break; case BEGIN: if(m != null) { nobj = new NamedObject(m,MARKER); object.push(nobj); built.addElement(m); applet.showStatus( "BuildGraph: Loaded Marker file!"); return true; } else { if(color != null) object.push(color); if(size != null) object.push(size); if(style != null) object.push(style); applet.showStatus("BuildGraph: Built Marker!"); return true; } default: errorAtLine("Incorrect keyword in MARKER specification"); return false; } } } /** * @return true if the build was successful */ protected boolean buildData(int type) { NamedObject nobj; DataSet data = new DataSet(); NamedObject ndata = new NamedObject(data,DATA); ParseFunction parsef = null; LoadData load = null; double xmin = 0.0; double xmax = 0.0; double ymin = 0.0; double ymax = 0.0; int nx = 0; int ny = 0; if(type == CDATA && !(graph instanceof Contour)) { errorAtLine("CDATA can only be used in CONTOUR!"); } while( true ) { nobj = (NamedObject)(object.pop()); debugMessage("Data",nobj.id); switch (nobj.id) { case NAME: ndata.setName((String)(nobj.getObject())); break; case MARKER_STYLE: data.marker = ((Integer)(nobj.getObject())).intValue(); break; case MARKER_SIZE: data.markerscale = (double)(((Integer)(nobj.getObject())).intValue()); break; case MARKER_COLOR: data.markercolor = (Color)(nobj.getObject()); break; case OFF: data.linestyle = 0; break; case ON: data.linestyle = 1; break; case COLOR: if(type == CDATA) { ((Contour)graph).setContourColor( (Color)(nobj.getObject())); } else { data.linecolor = (Color)(nobj.getObject()); } break; case URL: load = new LoadData(data); load.loadDataSet( (URL)(nobj.getObject()), graph); break; case FUNCTION: parsef = new ParseFunction((String)(nobj.getObject())); if(!parsef.parse()) { errorAtLine("Error in function definition!"); return false; } break; case XNUMBER: nx = ((Integer)(nobj.getObject())).intValue(); break; case XMIN: xmin = ((Double)(nobj.getObject())).doubleValue(); break; case XMAX: xmax = ((Double)(nobj.getObject())).doubleValue(); break; case YNUMBER: ny = ((Integer)(nobj.getObject())).intValue(); break; case YMIN: ymin = ((Double)(nobj.getObject())).doubleValue(); break; case YMAX: ymax = ((Double)(nobj.getObject())).doubleValue(); break; case BEGIN: if( parsef != null && type == CDATA ) { if( !(graph instanceof Contour) ) { errorAtLine("CDATA should only be used for Contours!"); return false; } double array[] = arrayFromFunction(parsef,nx,xmin,xmax, ny,ymin,ymax); if(array == null) { errorAtLine("Unable to build Data from Function"); return false; } ((Contour)graph).setRange(xmin,xmax,ymin,ymax); ((Contour)graph).setGrid(array,nx,ny); return true; } else if( parsef != null ) { double array[] = arrayFromFunction(parsef,nx,xmin,xmax); if(array == null) { errorAtLine("Unable to build Data from Function"); return false; } try { data.append(array,nx); object.push(ndata); datasets.addElement(ndata); built.addElement(data); return true; } catch(Exception e) { return false; } } else if( load == null ) { errorAtLine("No URL has been defined for Data!"); return false; } object.push(ndata); built.addElement(data); built.addElement(load); datasets.addElement(ndata); applet.showStatus("BuildGraph: Loading Data!"); return true; default: errorAtLine("Incorrect keyword in Data specification"); return false; } } } protected double[] arrayFromFunction(ParseFunction f, int nx, double xmin, double xmax) { double x; double y; double array[] = new double[2*nx]; double xinc = (xmax-xmin)/(nx-1); int count = 0; for(int i=0; itrue if the build was successful */ protected boolean buildAxis() { Stack attach = new Stack(); NamedObject nobj; Axis axis = new Axis(); NamedObject naxis = new NamedObject(axis,AXIS); int angle = 0; while( true ) { nobj = (NamedObject)(object.pop()); debugMessage("Axis",nobj.id); switch (nobj.id) { case NAME: naxis.setName((String)(nobj.getObject())); break; case TITLE: axis.title = (RTextLine)(nobj.getObject()); break; case LABEL_FONT: axis.label.setFont((Font)(nobj.getObject())); break; case LABEL_COLOR: axis.label.setColor((Color)(nobj.getObject())); break; case BOTTOM: axis.setPosition(Axis.BOTTOM); break; case TOP: axis.setPosition(Axis.TOP); break; case LEFT: axis.setPosition(Axis.LEFT); angle = 90; break; case RIGHT: axis.setPosition(Axis.RIGHT); angle = -90; break; case ATTACH: attach.push(new NamedObject(axis, (String)(nobj.getObject()),ATTACH)); break; case BEGIN: axis.g2d = (Graph2D)graph; axis.setTitleRotation(angle); object.push(naxis); while(attach.size() > 0) { object.push(attach.pop()); } built.addElement(axis); applet.showStatus("BuildGraph: Built Axis!"); return true; default: errorAtLine("Incorrect keyword in Data specification"); return false; } } } /** * @return true if the build was successful */ protected boolean buildGrid() { NamedObject nobj; NamedObject color = null; NamedObject grid = null; while( true ) { nobj = (NamedObject)(object.pop()); debugMessage("Grid",nobj.id); switch (nobj.id) { case OFF: grid = nobj; grid.setId(GRID_OFF); break; case ON: grid = nobj; grid.setId(GRID_ON); break; case COLOR: color = nobj; color.setId(GRID_COLOR); break; case BEGIN: if(grid != null) object.push(grid); if(color != null) object.push(color); return true; default: errorAtLine("Incorrect keyword in Grid specification"); return false; } } } /** * @return true if the build was successful */ protected boolean buildZero() { NamedObject nobj; NamedObject color = null; NamedObject zero = null; while( true ) { nobj = (NamedObject)(object.pop()); debugMessage("Zero",nobj.id); switch (nobj.id) { case OFF: zero = nobj; zero.setId(ZERO_OFF); break; case ON: zero = nobj; zero.setId(ZERO_ON); break; case COLOR: color = nobj; color.setId(ZERO_COLOR); break; case BEGIN: if(zero != null) object.push(zero); if(color != null) object.push(color); return true; default: errorAtLine("Incorrect keyword in Zero specification"); return false; } } } /** * output the parsed error message with the line number of the line * that triggered the error. * @param s Message to ouput */ private void errorAtLine(String s) { System.out.println("Error at line "+lineno+": "+s); applet.showStatus("Error at line "+lineno+": "+s); } /** * output the parsed debug message, appending line number, and token string * @param s Message to ouput * @param token token to be replaced with a string */ private void debugMessage(String s, int token) { String st = null; if(!debug) return; switch ( token ) { case DEBUG: st = null; break; case G2DINT: st = "G2DINT"; break; case GRAPH2D: st = "GRAPH2D"; break; case CONTOUR: st = "CONTOUR"; break; case TT_EOF: st = null; break; case TT_EOL: st = null; break; case URL: st = "URL"; break; case ATTACH: st = "ATTACH"; break; case STYLE: st = "STYLE"; break; case SIZE: st = "SIZE"; break; case COLOR: st = "COLOR"; break; case NAME: st = "NAME"; break; case BEGIN: st = "BEGIN"; break; case END: st = "END"; break; case MARKER: st = "MARKER"; break; case AXIS: st = "AXIS"; break; case TITLE: st = "TITLE"; break; case DATA: st = "DATA"; break; case LABEL: st = "LABEL"; break; case FONT: st = "FONT"; break; case BOTTOM: st = "BOTTOM"; break; case TOP: st = "TOP"; break; case LEFT: st = "LEFT"; break; case RIGHT: st = "RIGHT"; break; case ON: st = "ON"; break; case OFF: st = "OFF"; break; case PLAIN: st = "PLAIN"; break; case BOLD: st = "BOLD"; break; case ITALIC: st = "ITALIC"; break; case MARKER_STYLE: st = "MARKER_STYLE"; break; case MARKER_COLOR: st = "MARKER_COLOR"; break; case MARKER_SIZE: st = "MARKER_SIZE"; break; case LABEL_COLOR: st = "LABEL_COLOR"; break; case LABEL_FONT: st = "LABEL_FONT"; break; case GRID_COLOR: st = "GRID_COLOR"; break; case GRID: st = "GRID"; break; case GRID_OFF: st = "GRID_OFF"; break; case GRID_ON: st = "GRID_ON"; break; case ZERO_COLOR: st = "ZERO_COLOR"; break; case ZERO: st = "ZERO"; break; case ZERO_OFF: st = "ZERO_OFF"; break; case ZERO_ON: st = "ZERO_ON"; break; case MARKER_URL: st = "MARKER_URL"; break; case FUNCTION: st = "FUNCTION"; break; case XRANGE: st = "XRANGE"; break; case YRANGE: st = "YRANGE"; break; case NUMBER: st = "NUMBER"; break; case SQUARE: st = "SQUARE"; break; case BACKGROUND: st = "BACKGROUND"; break; default: st = "UNKNOWN"; break; } if(st != null) System.out.println("("+lineno+") "+s+": "+st); } } /** * this is a structure class used exclusively BuildGraph. * the class contains an Object variable, a String name identifying the object, * and/or an integer token identifying the object. * */ class NamedObject extends Object { protected Object o = null; protected String s = null; protected int id = ScanWord.UNKNOWN; public NamedObject() { } public NamedObject(Object o) { this.o = o; } public NamedObject(Object o, String s) { this.o = o; this.s = s; } public NamedObject(Object o, String s, int id) { this.o = o; this.s = s; this.id = id; } public NamedObject(Object o, int id) { this.o = o; this.id = id; } public NamedObject(int id) { this.id = id; } public NamedObject(String s) { this.s = s; } public Object getObject() { return o; } public String getName() { return s; } public int getId() { return id; } public void setObject(Object o) { this.o = o; } public void setId(int id) { this.id = id; } public void setName(String s) { this.s = s; } public boolean equals(Object obj) { if(obj instanceof NamedObject) { NamedObject nobj = (NamedObject)obj; if( nobj.s == null && s != null || nobj.s != null && s == null || nobj.id != this.id || !nobj.s.equals(s) ) return false; if( nobj.o.equals(o) ) return true; } return false; } }