
/*

 AOTParse.jj

 Autor: Matthias Nickles (Matthias_Nickles@msn.com)

 (c)1997 LMU Muenchen

 Eingabedatei (Baum-Quellcode-Parser)
 fuer JavaCC (v0.6.1, (c)97 Sun Microsystems)

 Source v0.10.0

 Die von JavaCC hieraus generierten Dateien AOTParse.java usw.
 stellen den Quellcode fuer einen praediktiven Parser fuer 
 Categories(.cat)-Dateien (Und-/Oder-Baeume in Textform 
 sowie Constraints und Selektionen (fuer Bookmarks)) dar. 

 Naeheres siehe Categories-Dokumentation.

*/


options {
  STATIC = false;  // (siehe Prozedur Node())
  LOOKAHEAD = 1;
  DEBUG_PARSER = false;
  ERROR_REPORTING = true;
  USER_TOKEN_MANAGER = false; // muss false sein wg. STATIC=false
  USER_CHAR_STREAM = false; // ebenso
  JAVA_UNICODE_ESCAPE = false;
  UNICODE_INPUT = false;
}


PARSER_BEGIN(AOTParse)

//package AOT;

import java.util.*;


class AOTParse {

 static String unescapeString(String in) {
 // entfernt Anfuehrungszeichen um in, loest Fluchtzeichen in in auf

  String out = "";

  char c;

  for (int i = 1; i<in.length()-1; i++) {

   c = in.charAt(i);

   if(c=='\\') {

    ++i;

	if(in.charAt(i)=='n')
	 c = '\n';
	else if(in.charAt(i)=='r')
	 c = '\r';
	else if(in.charAt(i)=='t')
	 c = '\t';
    else
     c = in.charAt(i);

   }

   out += c;

  }

  return out;

 }

 static String escapeString(String in) {
 // fuegt Fluchtzeichen vor reservierten Zeichen ein

  if(in==null)
   return "";

  String out = "";

  char c;

  for (int i = 0; i<in.length(); i++) {

   c = in.charAt(i);

   if(c=='\\'||c=='\"')
    out += "\\"+c;
   else if(c=='\n')
    out += "\\n";
   else if(c=='\r')
    out += "\\r";
   else if(c=='\t')
    out += "\\t";
   else
    out += c;

  }

  return out;

 }

}

PARSER_END(AOTParse)

IGNORE_IN_BNF :
{}
{
  " "
| "\t"
| "\r"
| "\n"
| <LineComment: "//" (~["\n","\r"])* ["\n","\r"] >
| <CComment: "/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/" >
}

TOKEN :
{}
{
  <StringToken: "\""(~["\"","\\"] | "\\"["\"", "n", "r", "t", "\\"])*"\"" >   
  | <IntegerToken: (<Digit>)+ >
  | <#Digit: ["0" - "9"] >
  | <#letter: ["a"-"z"] >
  | <#Letter: <letter> | ["A"-"Z", "_"] >
  | <Boolean: "yes"|"no"|"true"|"false" >
  | <AndToken: "and" >
  | <OrToken: "or" >
  | <iOrToken: "ior" >
  | <TextToken: "text" >
  | <IncludeToken: "include" >
  | <RowsToken: "rows" >
  | <ColsToken: "columns" >
  | <HelpToken: "help"|"commentary" >
  | <LabelToken: "label" >
  | <CollapsedToken: "collapsed" >
  | <DocumentToken: "categories" >
  | <ConstraintToken: "constraint" >
  | <SuspendedToken: "suspended" >
  | <BookmarkToken: "selection" >
  | <IdToken: <letter> (<Letter>|<Digit>)* >
}

Node document(Node parent, Edge edge, Constraint[][] consp, Bookmark[][] bookmp) :
{
  Node n;
}
{
  (( 
    <DocumentToken> "(" n = node(parent, edge) ")" "." 

    consp[0] = constraints()

	bookmp[0] = bookmarks()

  )
  |
  ( n = node(parent, edge) { consp[0] = null; bookmp[0] = null; } ))
  
  { return n; }

}

Node node(Node parent, Edge edge) :
{

  Node[] c;
  Node n;

  Token leaf_text_token, rows_token, columns_token, url_token;

  int rows, columns;
  String leaf_text, url;
}
{

  <AndToken> "(" { n = new AND_Node(parent, edge, null, null, false); }
  "[" c = children(n) "]" [ And_Attributes((AND_Node)n) ] ")" { n.set_children(c); return n; } 

| <OrToken> "(" { n = new OR_Node(parent, edge, null, null, false); }
  "[" c = children(n) "]" [ Or_Attributes((OR_Node)n) ] ")" { n.set_children(c); return n; }

| <iOrToken> "(" { n = new iOR_Node(parent, edge, null, null, false); }
  "[" c = children(n) "]" [ iOr_Attributes((iOR_Node)n) ] ")" { n.set_children(c); return n; }

| <TextToken> "(" { n = new Text_Node(parent, edge, null, false, "", AOTreeString.DEFAULT_TEXT_ROWS, AOTreeString.DEFAULT_TEXT_COLUMNS); }
  [ leaf_text_token = <StringToken> { ((Text_Node)n).set_leaf_text(unescapeString(leaf_text_token.image)); } ] 
  [ Text_Attributes((Text_Node)n) ]
  ")" { return n; }

| <IncludeToken> "(" url_token = <StringToken> ")"
  { // Include-Datei expandieren

   url = unescapeString(url_token.image);

   String current_directory_before = AOT.Aot.current_directory!=null?new String(AOT.Aot.current_directory):null;

   String file_content = Document.read_tree(url); // inkl. Wechsel in's Verzeichnis von url

   if(file_content==null) {

    AOT.Aot.current_directory = current_directory_before;

    return null;

   }
  
   AOTreeString source = new AOTreeString(null, file_content);
 
   StringBuffer message = new StringBuffer();

   Constraint[][] dummy1 = new Constraint[1][];

   Bookmark[][] dummy2 = new Bookmark[1][];

   Node subtree = source.parse(parent, edge, message, dummy1, dummy2); 
   // (^ Aufruf setzt unbedingt voraus, dass die javacc-Option STATIC=false gesetzt ist)

   AOT.Aot.current_directory = current_directory_before;

   if(subtree==null) {

    System.out.println("Error: Parser error in include-file "+url); // (Debugging-Info)

    InfoDialog.info(AOT.APPLET_NAME+" Error", "Could not parse include-file "+url+":\n"+message, InfoDialog.OK, "cats_src.html#grammatik");

   } else {

    System.out.println("Parse of include-file "+url+" was successful"); // (Debugging-Info)

    subtree.set_name(url); 
      // Der (Datei-)Name url des Knotens ist im Baumdiagramm 
      // nur fuer den Superuser sichtbar und bewirkt ggf. beim Speichern des Baums,
      // dass der Unterbaum subroot in der Datei url statt in der Vater-Datei abgelegt wird.
      // Um dieses Prinzip zu verallgemeinern, erhaelt der Wurzelknoten root der Vater-Datei
      // deren Dateinamen.
   }

   return subtree;

  }
}

void And_Attribute(AND_Node target) :
{
}
{

 Common_Attribute(target)

 // | ... (weitere Attribute speziell fuer Und-Knoten)
 
}

void And_Attributes(AND_Node target) :
{
}
{

 "," And_Attribute(target) [ And_Attributes(target) ]
 
}

void Or_Attribute(OR_Node target) :
{
}
{

 Common_Attribute(target)

 // | ... (weitere Attribute speziell fuer Oder-Knoten)

}

void Or_Attributes(OR_Node target) :
{
}
{

 "," Or_Attribute(target) [ Or_Attributes(target) ]

}

void iOr_Attribute(iOR_Node target) :
{
}
{

 Common_Attribute(target)

 // | ... (weitere Attribute speziell fuer inklusive-Oder-Knoten)

}

void iOr_Attributes(iOR_Node target) :
{
}
{

 "," iOr_Attribute(target) [ iOr_Attributes(target) ]

}

void Text_Attribute(Text_Node target) :
{
 Token rows_token, cols_token;
}
{

  Common_Attribute(target)
  |
  ( <RowsToken> "=" rows_token = <IntegerToken> { target.set_rows(Integer.parseInt(rows_token.image)); } )
  |
  ( <ColsToken> "=" cols_token = <IntegerToken> { target.set_columns(Integer.parseInt(cols_token.image)); } )

  // | ... (weitere Attribute speziell fuer Textblatt-Knoten)

}

void Text_Attributes(Text_Node target) :
{
}
{

 "," Text_Attribute(target) [ Text_Attributes(target) ]
 
}

void Common_Attribute(Node target) :
{
  Token collapsed_token;
  Token help_token;
}
{
 
 ( <CollapsedToken> "=" collapsed_token = <Boolean> { target.set_collapsed(collapsed_token.image.equalsIgnoreCase("yes")||collapsed_token.image.equalsIgnoreCase("true")); } )
 |
 ( <HelpToken> "=" help_token = <StringToken> { target.set_help(unescapeString(help_token.image)); } )

  // | ... (weitere Attribute fuer alle Knotentypen)

}


Node[] children(Node parent) :
{
  Vector children_temp;
  Node n;
}
{

  n = child(parent) { children_temp = new Vector(); children_temp.addElement(n); }

  ("," n = child(parent) { children_temp.addElement(n); })*

  {

   Node[] children = new Node[children_temp.size()];

   children_temp.copyInto(children);

   return children;

  }

| { return new Node[0]; /* (ueblicherweise bei And([]))*/ }

}


Node child(Node parent) :
{
  Edge edge;
  Node n;
}
{

  edge = parse_edge() ":" n = node(parent, edge) 

  { return n; }

}

Edge parse_edge() :
{
 
 Edge e;

 Token id_token;

}
{
 
 id_token = <IdToken> { e = new Edge("", null, new String(id_token.image)); }
 
 [ "(" [ Edge_Attributes(e) ] ")" ]

 { return e; }

}

void Edge_Attribute(Edge target) :
{

 Token label_token, help_token;

}
{

  ( [ <LabelToken> "=" ] label_token = <StringToken> { target.set_label(unescapeString(label_token.image)); } )
  |
  ( <HelpToken> "=" help_token = <StringToken> { target.set_help(unescapeString(help_token.image)); } )

  // | ... (weitere Attribute speziell fuer Kanten)

}

void Edge_Attributes(Edge target) :
{
}
{

 Edge_Attribute(target) [ "," Edge_Attributes(target) ]
 
}

Constraint[] constraints() :
{
  Vector constraints_temp;
  Constraint c;
}
{
 
  { constraints_temp = new Vector(); }

  (c = constraint() { constraints_temp.addElement(c); })*

  {

   Constraint[] constraints_array = new Constraint[constraints_temp.size()];

   constraints_temp.copyInto(constraints_array);

   return constraints_array;

  }

}

Constraint constraint() :
{

 Constraint constraint;

 String selection_a, selection_b;

 Vector selections_temp;

}
{

 { constraint = new Constraint(); selections_temp = new Vector(); }

 <ConstraintToken> "(" "(" selection_a = selections("\r\n  ") ")" "," 

 { selections_temp.addElement("("+selection_a+")");  }
 
 "[" 
 
  ( "(" selection_b = selections("\r\n  ") ")" 
 
    { selections_temp.addElement("("+selection_b+")"); } [ "," ]
  )*

 "]" 
 
 [ Constraint_Attributes(constraint) ]

 ")" "."

 {

  constraint.patterns = new String[selections_temp.size()];

  selections_temp.copyInto(constraint.patterns);

  return constraint;

 }

}

String selections(String indent) :
{ // Achtung: die aeusseren Klammern von (selection) werden hier nicht gematcht !

 String sels;

 String tmp;

}
{
 
 { sels = new String(); }

 tmp = selection(indent) { sels += tmp; } 

 ( "," { sels += ","; } tmp = selection(indent) { sels += tmp; } )*

 { return sels; }

}

String selection(String indent) :

{ // Matching einer(!) Selektion muss immer per selections() erfolgen,
  // da eine Selektion (bei Weglassen der aeusseren Klammern) kein Baum ist!

 String sel;

 String tmp;

 Token token;

}
{

  { sel  = new String(); }

 /* selection() kann leider nicht als ein einziges regulaeres Token 
    gematcht werden (Konflikte in lexikalischer Phase).
    Daher ist folgender - eigentl. unverhaeltnismaessiger - Aufwand noetig. */
  
  ( ( "_" { sel += "_"; } )
   |
   ( token = <StringToken> { sel += /*"\""+unescapeString(*/token.image/*)+"\""*/; })
   |
   ( token = <IdToken> { sel += indent+token.image; }
     ( 
	  "(" { sel += "("; } 
	  tmp = selections(indent+"  ") { sel += tmp; } 
	  ")" { sel += ")"; } 
	 )?

   ) )?
  
 { return sel; }

}


void Constraint_Attribute(Constraint target) :
{

 Token label_token, help_token, suspended_token;

}
{

 ( [ <LabelToken> "=" ] label_token = <StringToken> { target.id = unescapeString(label_token.image); } )
 |
 ( <HelpToken> "=" help_token = <StringToken> { target.help = unescapeString(help_token.image); } )
 |
 ( <SuspendedToken> "=" suspended_token = <Boolean> { target.suspended = suspended_token.image.equalsIgnoreCase("true")||suspended_token.image.equalsIgnoreCase("yes"); } )

 // | ... (ggf. weitere Attribute speziell fuer einen Constraint)
 
}

void Constraint_Attributes(Constraint target) :
{
}
{

 "," Constraint_Attribute(target) [ Constraint_Attributes(target) ]
 
}


Bookmark[] bookmarks() :
{
  Vector bookmarks_temp;
  Bookmark c;
}
{
 
  { bookmarks_temp = new Vector(); }

  (c = bookmark() { bookmarks_temp.addElement(c); })*

  {

   Bookmark[] bookmarks_array = new Bookmark[bookmarks_temp.size()];

   bookmarks_temp.copyInto(bookmarks_array);

   return bookmarks_array;

  }

}

Bookmark bookmark() :
{

 Bookmark bookmark;

 String selection_a;

}
{

 { bookmark = new Bookmark("Noname", null); }

 <BookmarkToken> "(" "(" selection_a = selections("\r\n  ") ")"

 { bookmark.content = "("+selection_a+")"; }
 
 [ Bookmark_Attributes(bookmark) ]

 ")" "."

 { return bookmark; }

}


void Bookmark_Attribute(Bookmark target) :
{

 Token label_token;

}
{

 ( [ <LabelToken> "=" ] label_token = <StringToken> { target.name = unescapeString(label_token.image); } )

 // | ... (ggf. weitere Attribute speziell fuer eine Bookmark-Selektion )
 
}

void Bookmark_Attributes(Bookmark target) :
{
}
{

 "," Bookmark_Attribute(target) [ Bookmark_Attributes(target) ]
 
}

