/*
// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Susan Mniszewski (Los Alamos Nat. Lab),
	      Patricia K. Fasel (Los Alamos Nat. Lab.), Jonathan Berry
// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.
// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.
// Last File Update: 7-Aug-1997
// 
*/
%{
/*================================================================
   LINK Graph Language Input System 
	ver 1.0 by Sue Mniszewski
	ver 2.0 by Patricia Fasel, for recursive descent parsing of subgraphs
	YACC input
================================================================*/
#include <string.h>
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <strstream.h>
#include <LINK/graph/Graph.h>
#include <LINK/graph/UHyperGraph.h>
#include <LINK/graph/DHyperGraph.h>
#include <LINK/graph/UBinGraph.h>
#include <LINK/graph/DBinGraph.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/Edge.h>
#include <LINK/graph/Attribute.h>
#include <LINK/basic/Set.h>
#include <LINK/basic/Sequence.h>
#define UNDEFINED_ATTR    -20
#define MULTIPLY_DEFINED  -21
#define VERTEX_UNDECLARED -22
void yyerror(char *str);
int yylex(void);
enum	Edge_type	{ bin, hyper };
enum	Direct_type	{ directed, undirected, mixed };
/******************************************************************************/
/* the following indicate the most specific graph type matching that parsed.  */
/* they determine the graph type of the parsed graph when none is specified.  */
/******************************************************************************/
int			auto_type;	/* true if no graph type specified    */
int			bingraph;	/* true as long as we dont see |E|neq2*/
int			mult_seen;	/* have we seen multiedges yet?       */
int			und_seen;	/* have we seen an undir. edge yet?   */
int			dir_seen;	/* have we seen a dir. edge yet?      */
/******************************************************************************/
Edge_type		graph_type;	/* indicates what the user specified */
Direct_type		graph_direct;	/* indicates what the user specified */
extern	Graph*		new_graph;	/* defined in parseGraph.cpp	     */
extern	int		line_count;
Sequence<Vertex*>	seq_vs;
Sequence<Vertex*>	seq_supervs;
Vertex*			yyvertex;
Edge*			yyedge;
Array<Graph*>		yygraph;
Array<Vertex*>		yysuper;
int			yycur = 0;
int			yymain = 0;
void	CircleLayout(GraphView*, Graph*);
#define VERTEX 0
#define EDGE   1
#include <LINK/basic/Iterator.h>
#include <LINK/basic/List.h>
#include <LINK/graph/Attribute.h>
void updateGraphObjectAttribute(GraphObject *go, int flag)
{
	List<AttributeBase*> alist = go->attributes();
	Iterator<AttributeBase*> get_attr(&alist);
	AttributeBase* attribute;
	while (get_attr(attribute)) {
		char *name, *n = (char*) attribute->name();
		if (strncmp(n, "_go_", 4) == 0) {
			getAttribute(go, n, name);
			GraphObject *attr_value; 
			if (flag==VERTEX) {
				attr_value = new_graph->findVertexByName(name);
			} else
				attr_value = new_graph->findEdgeByName(name);
			setAttribute(go, n+4, attr_value);
		}
	}
}
void  updateVertexPtrAttributes(Graph *new_graph)
{
	int i, order = new_graph->order();
	char *name;
	Vertex** vertices = new_graph->vertexStart();
	for (i=0; i<order; i++) 
		updateGraphObjectAttribute(vertices[i], VERTEX);
}
void  updateEdgePtrAttributes(Graph *new_graph)
{
	char *name;
	const MSet<Edge*>& edges = new_graph->edges();
	Iterator<Edge*> get_edge(&edges);
	Edge *e;
	while (get_edge(e)) 
		updateGraphObjectAttribute(e, EDGE);
}
void removeTemporaryAttributes(Graph *g)
{
	List<AttributeBase*> alist = g->attributes();
	Iterator<AttributeBase*> get_attr(&alist);
	AttributeBase* attribute;
	while (get_attr(attribute)) 
		if (strncmp(attribute->name(), "_go_", 4) == 0)
			deleteAttribute(g, attribute->name());
}
%}
%union {
  void	      *STK;	   /* pointer to stack    */
  char        *STR;        /* string          */
  int          NUM;        /* integer         */
  float        FLT;        //  used to be int with comment:/* scaled float    */
  double       DBL;
}
%token LBRACE
%token RBRACE
%token LBRACKET
%token RBRACKET
%token LPAREN
%token RPAREN
%token LDIRECT
%token RDIRECT
%token COMMA
%token ABSTRACTGRAPH
%token MHYPERGRAPH
%token MUHYPERGRAPH
%token MDHYPERGRAPH
%token MBINGRAPH
%token MUBINGRAPH
%token MDBINGRAPH
%token HYPERGRAPH
%token UHYPERGRAPH
%token DHYPERGRAPH
%token BINGRAPH
%token UBINGRAPH
%token DBINGRAPH
%token VERTICES 
%token EDGES 
%token LOCATION 
%token SUBGRAPH 
%token IDENT
%token INT_ATTR
%token STR_ATTR
%token DBL_ATTR
%token VPTR_ATTR
%token EPTR_ATTR
%token STR_CONST
%token INT_CONST
%token FLT_CONST
%token DBL_CONST
%token ERROR_TOKEN	
%type <STR> obj_name
%type <DBL> number
%%
/* --------------------------------------------------------------------------*/
graph_main	: graph_decl
    {
    if (auto_type) {
	if (bingraph) {
	    if (mult_seen) {
	       if (und_seen && dir_seen)
		 new_graph = new MBinGraph(*(MBinGraph*)yygraph[yymain],1);
	       else if (dir_seen)
		 new_graph = new MDBinGraph(*(MDBinGraph*)yygraph[yymain],1);
	       else
		 new_graph = new MUBinGraph(*(MUBinGraph*)yygraph[yymain],1);
	    } else {
	       if (und_seen && dir_seen)
		 new_graph = new BinGraph(*(BinGraph*)yygraph[yymain],1);
	       else if (dir_seen)
		 new_graph = new DBinGraph(*(DBinGraph*)yygraph[yymain],1);
	       else
		 new_graph = new UBinGraph(*(UBinGraph*)yygraph[yymain],1);
	    }
	} else {
	    if (mult_seen) {
	       if (und_seen && dir_seen)
		 new_graph=new MHyperGraph(*(MHyperGraph*)yygraph[yymain],1);
	       else if (dir_seen)
		 new_graph=new MDHyperGraph(*(MDHyperGraph*)yygraph[yymain],1);
	       else
		 new_graph=new MUHyperGraph(*(MUHyperGraph*)yygraph[yymain],1);
	    } else {
	       if (und_seen && dir_seen)
		 new_graph=new HyperGraph(*(HyperGraph*)yygraph[yymain],1);
	       else if (dir_seen)
		 new_graph=new DHyperGraph(*(DHyperGraph*)yygraph[yymain],1);
	       else
		 new_graph=new UHyperGraph(*(UHyperGraph*)yygraph[yymain],1);
	    }
	}
	yygraph.remove(yygraph[yymain]);
	delete yygraph[yymain]; 
    } else
        new_graph = yygraph[yymain];
    // graphobject attributes (ex: pred) must be set now.  When they
    // were parsed, a temporary attribute named _go_<attrname> was created.
    // Now we must go through the graph and use this attribute to look up
    // the appropriate graphobjects.
    updateVertexPtrAttributes(new_graph);
    updateEdgePtrAttributes(new_graph);
    removeTemporaryAttributes(new_graph);
    // open the subgraphs if specified (
    }
    ;
graph_decl	: LBRACE graph_desc graph_deflist RBRACE
                | LBRACE{
			auto_type = TRUE;
			bingraph =  TRUE;	/* these ultimately determine*/
			mult_seen = FALSE;	/* graph type.		     */
			und_seen =  FALSE;
			dir_seen =  FALSE;
		        graph_type = hyper;	/* parse with this type */
		        graph_direct = mixed;	/* assumed.             */
		        yygraph[yycur] = new MHyperGraph();
		        }
		  graph_deflist RBRACE
		;
graph_desc	: graph_type LPAREN graph_attrs RPAREN
		| graph_type LPAREN RPAREN
		| graph_type 
                | LPAREN 
                  {
			auto_type = TRUE;
			bingraph =  TRUE;	/* these ultimately determine*/
			mult_seen = FALSE;	/* graph type.		     */
			und_seen =  FALSE;
			dir_seen =  FALSE;
		        graph_type = hyper;	/* parse with this type */
		        graph_direct = mixed;	/* assumed.             */
		        yygraph[yycur] = new MHyperGraph();
		  }
		  graph_attrs RPAREN
		;
graph_deflist	: vertices edges
		;
graph_type	: ABSTRACTGRAPH
		    {}
		| ABSTRACTGRAPH MHYPERGRAPH	
		    {
		        graph_type = hyper;
		        graph_direct = mixed;
		        yygraph[yycur] = new MHyperGraph();
		    }
		| ABSTRACTGRAPH HYPERGRAPH	
		    {
		        graph_type = hyper;
		        graph_direct = mixed;
		        yygraph[yycur] = new HyperGraph();
		    }
		| ABSTRACTGRAPH MUHYPERGRAPH	
		    {
			graph_type = hyper;
			graph_direct = undirected;
			yygraph[yycur] = new MUHyperGraph();
		    }
		| ABSTRACTGRAPH UHYPERGRAPH	
		    {
			graph_type = hyper;
			graph_direct = undirected;
			yygraph[yycur] = new UHyperGraph();
		    }
		| ABSTRACTGRAPH MDHYPERGRAPH
		    {
			graph_type = hyper;
			graph_direct = directed;
                	yygraph[yycur] = new MDHyperGraph();
                    }
		| ABSTRACTGRAPH DHYPERGRAPH
		    {
			graph_type = hyper;
			graph_direct = directed;
                	yygraph[yycur] = new DHyperGraph();
		    }
		| ABSTRACTGRAPH MBINGRAPH
		    { 
			graph_type = bin;
			graph_direct = mixed;
                	yygraph[yycur] = new MBinGraph();
                    } 
		| ABSTRACTGRAPH BINGRAPH
		    { 
			graph_type = bin;
			graph_direct = mixed;
                	yygraph[yycur] = new BinGraph();
                    } 
		| ABSTRACTGRAPH MUBINGRAPH
		    { 
			graph_type = bin;
			graph_direct = undirected;
                	yygraph[yycur] = new MUBinGraph();
                    } 
		| ABSTRACTGRAPH UBINGRAPH
		    { 
			graph_type = bin;
			graph_direct = undirected;
                	yygraph[yycur] = new UBinGraph();
                    } 
		| ABSTRACTGRAPH MDBINGRAPH
		    {
			graph_type = bin;
			graph_direct = directed;
                	yygraph[yycur] = new MDBinGraph(); 
                    }
		| ABSTRACTGRAPH DBINGRAPH
		    {
			graph_type = bin;
			graph_direct = directed;
                	yygraph[yycur] = new DBinGraph(); 
                    }
		;
/* --------------------------------------------------------------------------*/
graph_attrs	: graph_attr 
		| graph_attrs graph_attr
		;
graph_attr      : rstr_g_attr	/* "reserved" string attribute (name, etc.)  */
		| rint_g_attr	/* "reserved" int attribute (color, etc.)   */
                | rdbl_g_attr   /* "reserved" dble  (x,y)*/
                | rvptr_g_attr  /* "reserved" Vertex* (pred)		     */
                | reptr_g_attr  /* "reserved" Edge*   (??)		     */
		| int_g_attr
                | flt_g_attr
                | dbl_g_attr
                | str_g_attr
		| LOCATION LPAREN number COMMA number RPAREN 
		{
		   setAttribute((GraphObject*) yygraph[yycur], "x", $<DBL>4);
		   setAttribute((GraphObject*) yygraph[yycur], "y", $<DBL>6);
		}
		;
rstr_g_attr: STR_ATTR LPAREN STR_CONST RPAREN
	    {
		if (!yygraph[yycur]->findAttr($<STR>1))
		     new Attribute<String>(yygraph[yycur], $<STR>1, $<STR>3);
		else {
		     setAttribute((GraphObject*)yygraph[yycur],$<STR>1,$<STR>3);
		}
	    }
	    ;
str_g_attr: IDENT LPAREN STR_CONST RPAREN
	    {
		if (!yygraph[yycur]->findAttr($<STR>1))
		     new Attribute<String>(yygraph[yycur], $<STR>1, $<STR>3);
		else
		     setAttribute((GraphObject*)yygraph[yycur],$<STR>1,$<STR>3);
	    }
	    ;
rint_g_attr: INT_ATTR LPAREN INT_CONST RPAREN
	      {
	      if (!yygraph[yycur]->findAttr($<STR>1))
		  new Attribute<int>(yygraph[yycur], $<STR>1, $<NUM>3);
	      else
		  setAttribute((GraphObject*)yygraph[yycur],$<STR>1,$<NUM>3);
	      }
	      ;
int_g_attr: IDENT LPAREN INT_CONST RPAREN
	      {
	      if (!yygraph[yycur]->findAttr($<STR>1))
		  new Attribute<int>(yygraph[yycur], $<STR>1, $<NUM>3);
	      else
		  setAttribute((GraphObject*)yygraph[yycur],$<STR>1,$<NUM>3);
	      }
	      ;
flt_g_attr: IDENT LPAREN FLT_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1))
		   new Attribute<float>(yygraph[yycur], $<STR>1, $<FLT>3);
		else
		   setAttribute((GraphObject*) yygraph[yycur], $<STR>1, $<FLT>3);
		}
		;
rvptr_g_attr: VPTR_ATTR LPAREN obj_name RPAREN
		{
		ostrstream oss;
		oss << "_go_" << $<STR>1 << ends;
		char *ns = oss.str();
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		  new Attribute<String>(yygraph[yycur], ns, $<STR>3);
		  new Attribute<Vertex*>(yygraph[yycur], $<STR>1, 
						(Vertex*)0);
		}
		delete ns;
		}
		;
reptr_g_attr: EPTR_ATTR LPAREN obj_name RPAREN
		{
		ostrstream oss;
		oss << "_go_" << $<STR>1 << ends;
		char *ns = oss.str();
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		  new Attribute<String>(yygraph[yycur], ns, $<STR>3);
		  new Attribute<Edge*>(yygraph[yycur], $<STR>1, 
						(Edge*)0);
		}
		delete ns;
		}
		;
rdbl_g_attr: DBL_ATTR LPAREN number RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1))
		  new Attribute<double>(yygraph[yycur], $<STR>1, $<DBL>3);
		else
		  setAttribute((GraphObject*) yygraph[yycur], $<STR>1, $<DBL>3);
		}
		;
dbl_g_attr: IDENT LPAREN DBL_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1))
		  new Attribute<double>(yygraph[yycur], $<STR>1, $<DBL>3);
		else
		  setAttribute((GraphObject*) yygraph[yycur], $<STR>1, $<DBL>3);
		}
		;
/* --------------------------------------------------------------------------*/
vertices	: vertex_hdr vertex_list RBRACKET 
		| vertex_hdr RBRACKET 
		;
vertex_hdr	: v_hdr
                | VERTICES v_hdr
		;
v_hdr 		: LBRACKET
		    {
			seq_vs.clear();
			seq_supervs.clear();
		    }
		;
vertex_list	: vertex     
		| vertex_list vertex
		;
vertex		: vertex_name LPAREN vertex_attrs RPAREN
		| vertex_name LPAREN RPAREN
		| vertex_name 
		;
vertex_name	: obj_name
		    {
	    	    yyvertex = yygraph[yymain]->addVertex($<STR>1);
		    yygraph[yymain]->removeVertex(yyvertex);
		    yygraph[yycur]->subgraphAddVertex(yyvertex);
		    if (yycur != yymain)
			// parent of this vertex is a subgraph
			setAttribute((GraphObject*) yyvertex, "x_parent",
			    yygraph[yycur]);
		    }
		;
obj_name	: STR_CONST	{ $$ = $<STR>1; }
		| IDENT    	{ $$ = $<STR>1; }
		| INT_CONST	{ char tmp[80];
				  sprintf(tmp, "%d", $<NUM>1);
				  extern char *newString(char *);
				  $$ = newString(tmp);
				}
		;
vertex_attrs	: vertex_attr 
		| vertex_attrs vertex_attr
		;
number		: INT_CONST	{ $$ = (double) $<NUM>1; }
		| FLT_CONST	{ $$ = (double) $<FLT>1; }
		| DBL_CONST	{ $$ = $<DBL>1;          }
		;
vertex_attr	: rstr_v_attr	/* "reserved" string attribute (name)        */
		| rint_v_attr	/* "reserved" int attribute (weight,..)      */
		| rdbl_v_attr   /* "reserved" dbl (x, y) */
                | rvptr_v_attr  /* "reserved" Vertex* (pred)		     */
                | reptr_v_attr  /* "reserved" Edge*   (??)		     */
		| int_v_attr	
		| flt_v_attr
		| dbl_v_attr
		| str_v_attr
		| LOCATION LPAREN number COMMA number RPAREN 
		    {
		    setAttribute((GraphObject*) yyvertex, "x", $<DBL>4);
		    setAttribute((GraphObject*) yyvertex, "y", $<DBL>6);
		    }
		| subgrph_attr LPAREN graph_decl RPAREN
		    { 
		    GraphObject* subgraph = (GraphObject*) yygraph[yycur];
		    GraphObject* supervertex = (GraphObject*) yysuper[yycur];
		    setAttribute(supervertex, "x_subgraph", yygraph[yycur]);
		    setAttribute(supervertex, "x_open", 0);
		    setAttribute(supervertex, "x_parent", yygraph[yycur-1]);
		    setAttribute(subgraph, "x_open", 0);
		    setAttribute(subgraph, "x_parent", yygraph[yycur-1]);
		    setAttribute(subgraph, "graph_name", supervertex->name());
		    setAttribute(subgraph, "x_supervertex", supervertex);
		    List<Vertex*>* supervertices;
		    getAttribute((GraphObject*) yygraph[yycur], 
			"x_supervertices", supervertices);
		    supervertices->append(yysuper[yycur]);
		    yyvertex = yysuper[yycur];
		    yycur--;
		    }
		;
subgrph_attr	: SUBGRAPH
		    {
		    yycur++;
		    yysuper[yycur] = yyvertex;
		    List<Vertex*>* supervertices;
		    getAttribute((GraphObject*) yygraph[yymain], 
			"x_supervertices", supervertices);
		    supervertices->append(yyvertex);
		    }
		;
rint_v_attr: INT_ATTR LPAREN INT_CONST RPAREN
                {
                if (!yygraph[yycur]->findAttr($<STR>1)) {
                       char tmp[80];
                       sprintf(tmp, "attribute %s undefined", $<STR>1);
                       yyerror(tmp);
		       return UNDEFINED_ATTR;
                } else 
                        setAttribute((GraphObject*) yyvertex,$<STR>1,$<NUM>3);
		}
                ;
int_v_attr: IDENT LPAREN INT_CONST RPAREN
                {
                if (!yygraph[yycur]->findAttr($<STR>1)) {
                       char tmp[80];
                       sprintf(tmp, "attribute %s undefined", $<STR>1);
                       yyerror(tmp);
		       return UNDEFINED_ATTR;
                } else 
                        setAttribute((GraphObject*) yyvertex,$<STR>1,$<NUM>3);
		}
                ;
flt_v_attr: IDENT LPAREN FLT_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyvertex, $<STR>1, $<FLT>3);
		}
		;
rdbl_v_attr: DBL_ATTR LPAREN number RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyvertex, $<STR>1, $<DBL>3);
		}
		;
rvptr_v_attr: VPTR_ATTR LPAREN obj_name RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
		}
		ostrstream oss;
		oss << "_go_" << $<STR>1 << ends;
		char *ns = oss.str();
		setAttribute((GraphObject*) yyvertex, ns, $<STR>3);
		delete ns;
		}
		;
reptr_v_attr: EPTR_ATTR LPAREN obj_name RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
		}
		ostrstream oss;
		oss << "_go_" << $<STR>1 << ends;
		char *ns = oss.str();
		setAttribute((GraphObject*) yyvertex, ns, $<STR>3);
		delete ns;
		}
		;
dbl_v_attr: IDENT LPAREN DBL_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyvertex, $<STR>1, $<DBL>3);
		}
		;
rstr_v_attr: STR_ATTR LPAREN STR_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyvertex, $<STR>1, $<STR>3);
		}
		;
str_v_attr: IDENT LPAREN STR_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyvertex, $<STR>1, $<STR>3);
		}
		;
/*---------------------------------------------------------------------------*/
edges		: edge_hdr edge_list RBRACE
		| edge_hdr RBRACE
		;
edge_hdr	: e_hdr
		| EDGES e_hdr
		;
e_hdr		: LBRACE
		    {
			seq_vs.clear();
			seq_supervs.clear();
		    }
		;
edge_list	: edge
		| edge_list edge
		;
edge		: edge_name edge_def LPAREN edge_attrlist RPAREN
		|           edge_def LPAREN edge_attrlist RPAREN
		| edge_name edge_def LPAREN RPAREN
		|           edge_def LPAREN RPAREN
		| edge_name edge_def 
		|           edge_def 
		;
edge_name	: obj_name 
		{/* this to override default $$ = $1 action */}
		;
edge_def	: dir_edge
		| und_edge
		;
edge_attrlist	: edge_attr  
		| edge_attrlist edge_attr
		;
edge_attr	: rstr_e_attr	/* "reserved" string attribute (name)        */
		| rint_e_attr	/* "reserved" int attribute (color,..)      */
		| rdbl_e_attr   /* "reserved" dbl  (x, y)*/
                | rvptr_e_attr  /* "reserved" Vertex* (pred)		     */
                | reptr_e_attr  /* "reserved" Edge*   (??)		     */
		| str_e_attr
		| int_e_attr
		| flt_e_attr
		| dbl_e_attr
		| LOCATION LPAREN number COMMA number RPAREN 
		    {
			setAttribute((GraphObject*) yyedge, "x", $<DBL>4);
			setAttribute((GraphObject*) yyedge, "y", $<DBL>6);
		    }
		;
rint_e_attr: INT_ATTR LPAREN INT_CONST RPAREN
                {
                if (!yygraph[yycur]->findAttr($<STR>1)) {
                       char tmp[80];
                       sprintf(tmp, "attribute %s undefined", $<STR>1);
                       yyerror(tmp);
		       return UNDEFINED_ATTR;
                } else 
                        setAttribute((GraphObject*) yyedge,$<STR>1,$<NUM>3);
		}
                ;
int_e_attr: IDENT LPAREN INT_CONST RPAREN
                {
                if (!yygraph[yycur]->findAttr($<STR>1)) {
                       char tmp[80];
                       sprintf(tmp, "attribute %s undefined", $<STR>1);
                       yyerror(tmp);
		       return UNDEFINED_ATTR;
                } else 
                        setAttribute((GraphObject*) yyedge,$<STR>1,$<NUM>3);
		}
                ;
flt_e_attr: IDENT LPAREN FLT_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyedge, $<STR>1, $<FLT>3);
		}
		;
rdbl_e_attr: DBL_ATTR LPAREN number RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyedge, $<STR>1, $<DBL>3);
		}
		;
dbl_e_attr: IDENT LPAREN DBL_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyedge, $<STR>1, $<DBL>3);
		}
		;
rvptr_e_attr: VPTR_ATTR LPAREN obj_name RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
		} 
		ostrstream oss;
		oss << "_go_" << $<STR>1 << ends;
		char *ns = oss.str();
		setAttribute((GraphObject*) yyedge, ns, $<STR>3);
		delete ns;
		}
		;
reptr_e_attr: EPTR_ATTR LPAREN obj_name RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
		}
		ostrstream oss;
		oss << "_go_" << $<STR>1 << ends;
		char *ns = oss.str();
		setAttribute((GraphObject*) yyvertex, ns, $<STR>3);
		delete ns;
		}
		;
rstr_e_attr: STR_ATTR LPAREN STR_CONST RPAREN
	    {
		if (!yygraph[yycur]->findAttr($<STR>1))
		     new Attribute<String>(yygraph[yycur], $<STR>1, $<STR>3);
		else {
		     setAttribute((GraphObject*) yyedge, $<STR>1, $<STR>3);
		}
	    }
	    ;
str_e_attr: IDENT LPAREN STR_CONST RPAREN
		{
		if (!yygraph[yycur]->findAttr($<STR>1)) {
		      char tmp[80];
		      sprintf(tmp, "attribute %s undefined", $<STR>1);
		      yyerror(tmp);
		      return UNDEFINED_ATTR;
	    	} else
		      setAttribute((GraphObject*) yyedge, $<STR>1, $<STR>3);
		}
		;
/* --------------------------------------------------------------------------*/
und_edge	: LBRACE vertex_set RBRACE
		    {
		    if (graph_type == bin && seq_vs.size() != 2) {
			printf("Binary edge must have two vertices\n");
		    } else {
		    	if (seq_vs.size() != 2) 
				bingraph = FALSE;
			if (yygraph[yymain]->isEdge(seq_vs))
				mult_seen = TRUE;
			und_seen = TRUE;
			Set<Vertex*> set_vs = seq_vs;
            		yyedge = yygraph[yymain]->addEdge(set_vs);
			yygraph[yymain]->removeEdge(yyedge);
			yygraph[yycur]->subgraphAddEdge(yyedge);
			Iterator<Vertex*> get_superv(&seq_supervs);
			Iterator<Vertex*> get_vertex(&seq_vs);
			Vertex* vertex;
			Vertex* superv;
			while (get_vertex(vertex) && get_superv(superv)) {
			    if (superv != vertex) {
				// must add edge to all supervertices in between
				Graph* parent;
				getAttribute((GraphObject*) vertex,
				    "x_parent", parent);
				Vertex* v;
				getAttribute((GraphObject*) parent,
				    "x_supervertex", v);
				while (v != superv) {
				    v->addEdge(yyedge);
				    getAttribute((GraphObject*) parent,
					"x_parent", parent);
				    getAttribute((GraphObject*) parent,
				        "x_supervertex", v);
				}
				superv->addEdge(yyedge);
				yyedge->replace(vertex, superv);
			    }
			}
        	    }
		    seq_vs.clear();
		    seq_supervs.clear();
		    }
		;
dir_edge	: LDIRECT vertex_seq RDIRECT
		    {
		    if (graph_type == bin && seq_vs.size() != 2) {
			printf("Binary edge must have two vertices\n");
		    } else {
		    	if (seq_vs.size() != 2) 
				bingraph = FALSE;
			if (yygraph[yymain]->isEdge(seq_vs))
				mult_seen = TRUE;
			dir_seen = TRUE;
            		yyedge = yygraph[yymain]->addEdge(seq_vs);
			yygraph[yymain]->removeEdge(yyedge);
			yygraph[yycur]->subgraphAddEdge(yyedge);
			Iterator<Vertex*> get_superv(&seq_supervs);
			Iterator<Vertex*> get_vertex(&seq_vs);
			Vertex* vertex;
			Vertex* superv;
			while (get_vertex(vertex) && get_superv(superv)) {
			    if (superv != vertex) {
				// must add edge to all supervertices in between
				Graph* parent;
				getAttribute((GraphObject*) vertex,
				    "x_parent", parent);
				Vertex* v;
				getAttribute((GraphObject*) parent,
				    "x_supervertex", v);
				while (v != superv) {
				    v->addEdge(yyedge);
				    getAttribute((GraphObject*) parent,
					"x_parent", parent);
				    getAttribute((GraphObject*) parent,
				        "x_supervertex", v);
				}
				superv->addEdge(yyedge);
				yyedge->replace(vertex, superv);
			    }
			}
		    }
		    seq_vs.clear();
		    seq_supervs.clear();
		    }
		;
vertex_set	: vertex_und	/* used to allow empty */
		| vertex_set vertex_und
		;
vertex_und	: obj_name
		    {
		    yyvertex = yygraph[yycur]->findVertexByName($<STR>1);
		    if (yyvertex) {
		    	seq_vs.insert(yyvertex);
		    	seq_supervs.insert(yyvertex);
		    } else {
			char tmp[80];
			sprintf(tmp, "vertex %s is undeclared", $<STR>1);
			yyerror(tmp);
		       return VERTEX_UNDECLARED;
		    }
		    }
		| obj_name LBRACKET obj_name RBRACKET
		    {
		    yyvertex = yygraph[yycur]->findVertexByName($<STR>1);
		    if (yyvertex) {
		    	seq_supervs.insert(yyvertex);
		    } else {
			char tmp[80];
			sprintf(tmp, "vertex %s is undeclared", $<STR>1);
			yyerror(tmp);
		        return VERTEX_UNDECLARED;
		    }
		    {
		    Graph *g;
		    getAttribute((GraphObject*) yyvertex, "x_subgraph", g);
		    yyvertex = g->findVertexByName($<STR>3);
		    if (yyvertex) {
		    	seq_vs.insert(yyvertex);
		    } else {
			char tmp[80];
			sprintf(tmp, "vertex %s is undeclared", $<STR>3);
			yyerror(tmp);
		        return VERTEX_UNDECLARED;
		    }
		    }
		    }
		;
vertex_seq	: vertex_dir	/* used to allow empty */
		| vertex_seq vertex_dir
		;
vertex_dir	: obj_name
		    {
		    yyvertex = yygraph[yycur]->findVertexByName($<STR>1);
		    if (yyvertex) {
		    	seq_vs.append(yyvertex);
		    	seq_supervs.append(yyvertex);
		    } else {
			char tmp[80];
			sprintf(tmp, "vertex %s is undeclared", $<STR>1);
			yyerror(tmp);
		        return VERTEX_UNDECLARED;
		    }
		    }
		| obj_name LBRACKET obj_name RBRACKET
		    {
		    yyvertex = yygraph[yycur]->findVertexByName($<STR>1);
		    if (yyvertex) {
		    	seq_supervs.append(yyvertex);
		    } else {
			char tmp[80];
			sprintf(tmp, "vertex %s is undeclared", $<STR>1);
			yyerror(tmp);
		        return VERTEX_UNDECLARED;
		    }
		    {
		    Graph *g;
		    getAttribute((GraphObject*) yyvertex, "x_subgraph", g);
		    yyvertex = g->findVertexByName($<STR>3);
		    //yyvertex = yygraph[yycur]->findVertexByName($<STR>3);
		    if (yyvertex) {
		    	seq_vs.append(yyvertex);
		    } else {
			char tmp[80];
			sprintf(tmp, "vertex %s is undeclared", $<STR>3);
			yyerror(tmp);
		        return VERTEX_UNDECLARED;
		    }
		    }	
		    }
		;
