content: package java_cup.runtime;
  
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  
  import javax.xml.stream.XMLStreamException;
  import javax.xml.stream.XMLStreamWriter;
  
  import java_cup.runtime.ComplexSymbolFactory.ComplexSymbol;
  import java_cup.runtime.ComplexSymbolFactory.Location;
  
  public abstract class XMLElement {
  	public abstract List<XMLElement> selectById(String s);
  	public static void dump(XMLStreamWriter writer, XMLElement elem, String ... blacklist) throws XMLStreamException {
  		dump(null,writer,elem,blacklist);
  	}
  	public static void dump(ScannerBuffer buffer, XMLStreamWriter writer, XMLElement elem, String ... blacklist) throws XMLStreamException {
  		writer.writeStartDocument("utf-8", "1.0");
  		writer.writeProcessingInstruction("xml-stylesheet","href=\"tree.xsl\" type=\"text/xsl\"");
  		writer.writeStartElement("document");
  		
  		if (blacklist.length>0) {
  			writer.writeStartElement("blacklist");
  			for (String s: blacklist){
  				writer.writeStartElement("symbol");
  				writer.writeCharacters(s);
  				writer.writeEndElement();
  			}
  			writer.writeEndElement();
  		}
  		
  		writer.writeStartElement("parsetree");
  		elem.dump(writer);
  		writer.writeEndElement();
  
  		if (buffer!=null){
  			writer.writeStartElement("tokensequence");
  			for (Symbol s:buffer.getBuffered()){
  				if (s instanceof ComplexSymbol){
  					ComplexSymbol cs = (ComplexSymbol)s;
  					if (cs.value!=null){
  						writer.writeStartElement("token");
  						writer.writeAttribute("name",cs.getName());
  						cs.getLeft().toXML(writer, "left");
  						writer.writeCharacters(cs.value+"");
  						cs.getRight().toXML(writer, "right");
  						writer.writeEndElement();
  					} else
  					{
  						writer.writeStartElement("keyword");
  						writer.writeAttribute("left",cs.getLeft()+"");
  						writer.writeAttribute("right",cs.getRight()+"");
  						writer.writeCharacters(cs.getName()+"");
  						writer.writeEndElement();
  					}
  				}
  				else 
  					if (s instanceof Symbol) {
  						writer.writeStartElement("token");
  						writer.writeCharacters(s.toString());
  						writer.writeEndElement();						
  					}
  			}
  			writer.writeEndElement();
  		}
  		writer.writeEndElement();
  		writer.writeEndDocument();
  		writer.flush();
  		writer.close();
  	}
  	protected String tagname;
          public String getTagname() { return tagname; }
  	public abstract Location right();
  	public abstract Location left();
  	protected abstract void dump(XMLStreamWriter writer) throws XMLStreamException;
          public List<XMLElement> getChildren() {return new LinkedList<XMLElement>(); };
          public boolean hasChildren() { return false; };
  	public static class NonTerminal extends XMLElement {
  	    public boolean hasChildren()  { return !list.isEmpty(); }
  	    public List<XMLElement> getChildren()  { return list; }
  	    @Override
  		public List<XMLElement> selectById(String s) {
  			LinkedList<XMLElement> response= new LinkedList<XMLElement>();
  			if (tagname.equals(s))
  				response.add(this);
  			for (XMLElement e : list){
  				List<XMLElement> selection =e.selectById(s);
  				response.addAll(selection);
  			}
  			return response;
  		}
  		private int variant;
  	    public int getVariant() {
  		return variant;
  	    }
  		LinkedList<XMLElement> list;
  		public NonTerminal(String tagname, int variant, XMLElement... l) {
  			this.tagname=tagname;
  			this.variant=variant;
  			list = new LinkedList<XMLElement>(Arrays.asList(l));
  		}
  
  		public Location left() {
  			for (XMLElement e : list){
  				Location loc = e.left();
  				if (loc!=null) return loc;
  			}
  			return null;	
  		}
  		public Location right() {
  			for (Iterator<XMLElement> it = list.descendingIterator();it.hasNext();){
  				 Location loc = it.next().right();
  				 if (loc!=null) return loc;
  			}
  			return null;
  		}
  
  		public String toString() {
  			if (list.isEmpty()){
  				return "<nonterminal id=\"" + tagname +"\" variant=\""+variant+"\" />" ;
  			}
  			String ret = "<nonterminal id=\"" + tagname +"\" left=\"" + left()
  					+ "\" right=\"" + right() + "\" variant=\""+variant+"\">";
  			for (XMLElement e : list)
  				ret += e.toString();
  			return ret + "</nonterminal>";
  		}
  		@Override
  		protected void dump(XMLStreamWriter writer) throws XMLStreamException {
  			writer.writeStartElement("nonterminal");
  			writer.writeAttribute("id", tagname);
  			writer.writeAttribute("variant", variant+"");
  //			if (!list.isEmpty()){
  				Location loc = left();
  				if (loc!=null) loc.toXML(writer, "left");
  //			}
  			for (XMLElement e:list)
  				e.dump(writer);
  			loc = right();
  			if (loc!=null) loc.toXML(writer, "right");
  			writer.writeEndElement();
  		}
  	}
  
  	public static class Error extends XMLElement {
  	    public boolean hasChildren()  { return false; }
  	    @Override
  		public List<XMLElement> selectById(String s) {
  			return new LinkedList<XMLElement>();
  		}
  		Location l,r;
  		public Error(Location l, Location r) {
  			this.l=l;
  			this.r=r;
  		}
  		public Location left() {	return l; 	}
  		public Location right() {	return r;	}
  
  		public String toString() {
  			return  "<error left=\"" + l + "\" right=\"" + r + "\"/>";
  		}
  		@Override
  		protected void dump(XMLStreamWriter writer) throws XMLStreamException {
  			writer.writeStartElement("error");
  			writer.writeAttribute("left", left()+"");
  			writer.writeAttribute("right", right()+"");
  			writer.writeEndElement();
  		}
  	}
  	
  	public static class Terminal extends XMLElement {
  	    public boolean hasChildren()  { return false; }
  	    public List<XMLElement> selectById(String s) {
  			List<XMLElement> ret = new LinkedList<XMLElement>();
  			if (tagname.equals(s)) { ret.add(this);	}
  			return ret;
  		};
  		Location l, r;
  		Object value;
  
  		public Terminal(Location l, String symbolname, Location r) {
  			this(l, symbolname, null, r);
  		}
  
  		public Terminal(Location l, String symbolname, Object i, Location r) {
  			this.l = l;
  			this.r = r;
  			this.value = i;
  			this.tagname = symbolname;
  		}
  
  		public Object   value() {return value; }
  		public Location left() {	return l; 	}
  		public Location right() {	return r;	}
  
  		public String toString() {
  			return (value == null) ? "<terminal id=\"" + tagname + "\"/>"
  					: "<terminal id=\"" + tagname + "\" left=\"" + l
  							+ "\" right=\"" + r + "\">" + value
  							+ "</terminal>";
  		}
  		@Override
  		protected void dump(XMLStreamWriter writer) throws XMLStreamException {
  			writer.writeStartElement("terminal");
  			writer.writeAttribute("id", tagname);
  			writer.writeAttribute("left", left()+"");
  			writer.writeAttribute("right", right()+"");
  			if (value!=null) writer.writeCharacters(value+"");
  			writer.writeEndElement();
  		}
  	}
  }
  