summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authorburaq <buraq@epfl.ch>2003-11-03 15:20:13 +0000
committerburaq <buraq@epfl.ch>2003-11-03 15:20:13 +0000
commit33d19305e4e00a38a167d3e159e92d90cd4de7ce (patch)
tree1546cf70dd7e06f1de1b9aae6bf346fdb8c14244 /sources
parentf2edc84853de62dbf63c9c1cda34d06e153ce88c (diff)
downloadscala-33d19305e4e00a38a167d3e159e92d90cd4de7ce.tar.gz
scala-33d19305e4e00a38a167d3e159e92d90cd4de7ce.tar.bz2
scala-33d19305e4e00a38a167d3e159e92d90cd4de7ce.zip
code cleanup + added parsing of content models
Diffstat (limited to 'sources')
-rw-r--r--sources/scala/tools/dtd2scala/DeclToSQL.scala75
-rw-r--r--sources/scala/tools/dtd2scala/DeclToScala.scala110
-rw-r--r--sources/scala/tools/dtd2scala/Main.scala192
-rw-r--r--sources/scala/tools/dtd2scala/MainHandler.scala97
-rw-r--r--sources/scala/tools/dtd2scala/XMLDecl.scala6
-rw-r--r--sources/scala/tools/dtd2scala/regexp/Alt.scala4
-rw-r--r--sources/scala/tools/dtd2scala/regexp/Eps.scala3
-rw-r--r--sources/scala/tools/dtd2scala/regexp/Node.scala3
-rw-r--r--sources/scala/tools/dtd2scala/regexp/PCDATA_.scala3
-rw-r--r--sources/scala/tools/dtd2scala/regexp/Parser.scala64
-rw-r--r--sources/scala/tools/dtd2scala/regexp/RegExp.scala15
-rw-r--r--sources/scala/tools/dtd2scala/regexp/Scanner.scala59
-rw-r--r--sources/scala/tools/dtd2scala/regexp/Seq.scala3
-rw-r--r--sources/scala/tools/dtd2scala/regexp/Star.scala3
-rw-r--r--sources/scala/tools/dtd2scala/regexp/Tokens.scala32
15 files changed, 416 insertions, 253 deletions
diff --git a/sources/scala/tools/dtd2scala/DeclToSQL.scala b/sources/scala/tools/dtd2scala/DeclToSQL.scala
new file mode 100644
index 0000000000..fd024270ec
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/DeclToSQL.scala
@@ -0,0 +1,75 @@
+package scala.tools.dtd2scala ;
+
+import scala.tools.dtd2scala.regexp._ ;
+
+import java.io.PrintWriter ;
+import scala.collection.mutable.{Set,Map,HashMap,HashSet} ;
+
+class DeclToSQL(fOut:PrintWriter,mName:String,elemMap:Map[String,ElemDecl ] ) {
+
+ abstract class Vertex {
+ var marked = false;
+ }
+ case class Label( name:String ) extends Vertex {
+ def this( n:Node ) = { this( n.name ) };
+ };
+ case class Attr(name:String) extends Vertex;
+ case class Rhs( ename:String, single:Set[Vertex], mult:Set[Vertex] ) {
+ var containsText = false;
+ def addSingle(n:Node):Unit = addSingle( new Label( n ) );
+ def addSingle(v:Vertex):Unit = if( single.contains(v) )
+ { single -= v; mult += v; }
+ else if( !mult.contains(v) )
+ { single += v; };
+
+ def addMult(n:Node):Unit = addMult( new Label( n ));
+ def addMult(v:Vertex):Unit = { single -= v; mult += v }
+ def this( ename:String ) = {
+ this(ename,new HashSet[Vertex],new HashSet[Vertex]);
+ }
+ override def toString() = { " single: "+single+" mult:"+mult +"\n"}
+ };
+
+ // step 1. forget order of children in a node type
+ // retain only cardinality
+
+ val looseMap:Map[String,Rhs] = {
+ var rhs:Rhs = null:Rhs;
+ def mults( r:RegExp ):Unit = r match {
+ case x:Node => rhs.addMult( x )
+ case Star( s ) => mults( s );
+ case Seq( rs@_* ) => rs.map( mults ); { }
+ case Alt( rs@_* ) => rs.map( mults ); { }
+ case _ => ;
+ }
+ def singles( r:RegExp ):Unit = r match {
+ case x:Node => rhs.addSingle( x )
+ case Star( s ) => mults( s );
+ case Seq( rs@_* ) => rs.map( singles ); { }
+ case Alt( rs@_* ) => rs.map( singles ); { }
+ case _ => ;
+ }
+ val m = new HashMap[String, Rhs];
+ for( val decl <- elemMap.values ) do {
+ //System.err.print("[processing element "+decl.name
+ // +" "+decl.contentModel+"]");
+ val orig = RegExp.parse( decl.contentModel );
+ //System.err.println("[parsing yields "+orig+"]");
+
+ rhs = new Rhs( decl.name );
+ singles( orig );
+ rhs.containsText = decl.containsText;
+ for( val aname <- decl.attribs.keys ) do rhs.addSingle( Attr( aname ));
+ m.update( decl.name, rhs );
+ }
+ m
+ }
+ def run = {
+ fOut.println( "-- this file is generated from a DTD");
+ fOut.println( "looseMap "+looseMap);
+ fOut.flush();
+ }
+
+
+}
+
diff --git a/sources/scala/tools/dtd2scala/DeclToScala.scala b/sources/scala/tools/dtd2scala/DeclToScala.scala
index 8b82edafa5..1b1210dae1 100644
--- a/sources/scala/tools/dtd2scala/DeclToScala.scala
+++ b/sources/scala/tools/dtd2scala/DeclToScala.scala
@@ -1,25 +1,18 @@
package scala.tools.dtd2scala ;
-import java.io.Writer ;
import java.io.PrintWriter ;
-import java.io.File ;
-import java.io.FileWriter ;
-import java.io.OutputStream ;
-import java.io.OutputStreamWriter ;
-import java.io.IOException ;
-
-//import java.util.Map ;
-//import java.util.Iterator ;
import scala.collection.Map ;
import scalac.util.Name ;
-import scalac.ast.parser.Scanner ;
-
-// 2do: remove setChildren, use escaped sequence in constructor call "Elem( x:_* )"
+import scalac.ast.parser.Scanner ; // for keywords
-class DeclToScala(fOut:PrintWriter, moduleName:String) {
+/** transforms a set of DTD declaraion to a scala source file.
+ */
+class DeclToScala(fOut:PrintWriter,
+ moduleName:String,
+ elemMap:Map[ String, ElemDecl ] ) {
- val DEFAULT_moduleName = "myXML";
+ final val DEFAULT_moduleName = "myXML";
final val COMPRESS_DEFAULT:String = "true"; // do hash-consing on load
@@ -43,16 +36,10 @@ class DeclToScala(fOut:PrintWriter, moduleName:String) {
//static final String HASHCODE_DEF = "override def hashCode():int = { getChildren.hashCode() + getAttribs.hashCode() + getName.hashCode() }";
final val IND_STEP:int = 5;
-/*
- def this() = { this(new PrintWriter( System.out ), DEFAULT_moduleName) }
- def this( outdir:File, moduleName:String ) = { this(
- new PrintWriter( new FileWriter( new File( outdir, moduleName+".scala" ))),
- moduleName) }
-*/
var fIndent:int = 0;
- def begin():Unit = {
+ def begin = {
fOut.println( "// this file is generated from a DTD");
fOut.print( "object " );
fOut.print( moduleName );
@@ -64,7 +51,7 @@ class DeclToScala(fOut:PrintWriter, moduleName:String) {
fOut.println("import scala.collection.mutable.HashMap ;");
}
- def end():Unit = {
+ def end = {
fOut.println("}");
fOut.flush();
fOut.close();
@@ -169,7 +156,7 @@ class DeclToScala(fOut:PrintWriter, moduleName:String) {
fOut.println( " ).match { Some(x) => x };");
}
- def printFactory( elemMap:Map[String,ElemDecl] ):Unit = {
+ def printFactory:Unit = {
printIndent();
fOut.println(
@@ -180,14 +167,14 @@ class DeclToScala(fOut:PrintWriter, moduleName:String) {
//"val res = new scala.HashMap[String,(scala.Map[String,String],scala.Seq[Element])=>Element] ;");
"val res = new HashMap[String, scala.Seq[scala.xml.Element] => scala.xml.Element] ;");
//JAVA: for(Iterator it = elemMap.keySet().iterator(); it.hasNext(); )
- elemMap.values.foreach( decl => {
+ for( val decl <- elemMap.values.elements ) do {
printIndent();
fOut.print( "res.update(\"" );
fOut.print( decl.name );
fOut.print( "\",(x:scala.Seq[scala.xml.Element] => ");
fOut.print( cookedCap( decl.name ));
fOut.println("( x:_* ) ));");
- });
+ };
printIndent();
fOut.println("res");
printIndent();
@@ -196,24 +183,21 @@ class DeclToScala(fOut:PrintWriter, moduleName:String) {
}
- def printContainsTextDef( elemMap:Map[String,ElemDecl] ):Unit = {
+ def printContainsTextDef:Unit = {
printIndent();
fOut.println("val _containsMap: Map[scala.String, boolean] = {");
fIndent = fIndent + IND_STEP;
printIndent();
fOut.println("val res = new HashMap[scala.String, boolean] ;");
- elemMap.values.foreach( decl => {
+ for( val decl <- elemMap.values.elements ) do {
printIndent();
fOut.print( "res.update(\"" );
fOut.print( decl.name );
fOut.print( "\",");
- if( decl.contentModel.indexOf("#PCDATA") != -1 )
- fOut.print("true")
- else
- fOut.print("false");
+ fOut.print( decl.containsText ); //write a boolean literal
fOut.println(");");
- });
+ };
printIndent();
fOut.println("res");
fIndent = fIndent - IND_STEP;
@@ -221,7 +205,7 @@ class DeclToScala(fOut:PrintWriter, moduleName:String) {
fOut.println( "}");
}
- def printLoaderDef():Unit = {
+ def printLoaderDef:Unit = {
printIndent();
fOut.print("def load( filename:String ):Element = load( filename, ");
fOut.print( COMPRESS_DEFAULT );
@@ -248,12 +232,10 @@ class DeclToScala(fOut:PrintWriter, moduleName:String) {
fIndent = fIndent - IND_STEP;
};
- def toScala( elemMap:Map[String,ElemDecl] ):Unit = {
- begin();
-
+def comment = {
fOut.println("/** the following elements are there");
- elemMap.values.foreach( decl => {
+ for( val decl <- elemMap.values.elements ) do {
fOut.print(" * ");
fOut.print( decl.name );
fOut.print(" : [");
@@ -261,44 +243,42 @@ class DeclToScala(fOut:PrintWriter, moduleName:String) {
fOut.println(']');
fOut.print(" * ");
fOut.println( "attribs: "+decl.attribs );
- } );
+ };
fOut.println("*/");
+}
- elemMap.values.foreach( decl => toScala( decl ) );
-
- printContainsTextDef( elemMap );
- printFactory( elemMap );
- printLoaderDef();
-
- end();
+ def run:Unit = {
+ begin;
+ comment;
+ for( val decl <- elemMap.values.elements ) do toScala( decl );
+ printContainsTextDef;
+ printFactory;
+ printLoaderDef;
+ end;
}
def toScala( decl:XMLDecl ):Unit = decl.match {
- case x:ElemDecl =>
- printClassDef( x );
-
- case AttrDecl( name, attrType ) =>
- if( attrType.equals("CDATA") ) {
- //printSetMethod(name);
- printGetMethod(name);
-
- } else { // ignore non-CDATA attribs
-
- System.err.print("[ignoring attribute \""
- +name+"\" of type \""
- +attrType+"\"]");
- }
- case _ =>
- System.err.println("unexpected XMLDecl"); System.exit(-1);
+ case x:ElemDecl => printClassDef( x );
+ case AttrDecl( name, "CDATA" ) => printGetMethod(name);
+ case AttrDecl( name, tpe ) => warning_attrib( name, tpe )
+ case _ => error("unexpected decl:"+decl);
} // toScala
+ private def warning_attrib(name:String,tpe:String) = {
+ System.err.print( "[ignoring attribute \"" );
+ System.err.print( name );
+ System.err.print( "\" of type \"" );
+ System.err.print( tpe );
+ System.err.print( "\"]" );
+ }
+
//
// cooking raw names
//
-def cooked( ckd:StringBuffer, raw:String, off:int ):String = {
+private def cooked( ckd:StringBuffer, raw:String, off:int ):String = {
for( val i <- List.range( off, raw.length()) ) do {
val _ = raw.charAt( i ).match {
case '-' =>
@@ -320,19 +300,19 @@ def cooked( ckd:StringBuffer, raw:String, off:int ):String = {
// type -> type$
// http-equiv -> http_equiv
-def cooked( raw:String ):String = {
+private def cooked( raw:String ):String = {
return cooked(new StringBuffer(), raw, 0);
}
// type -> Type$
// http-equiv -> Http_equiv
-def cookedCap( raw:String ):String = {
+private def cookedCap( raw:String ):String = {
val ckd:StringBuffer = new StringBuffer();
ckd.append( Character.toUpperCase( raw.charAt( 0 ) ));
return cooked( ckd, raw, 1);
}
- val toy:Scanner = new Scanner()
+ private val toy:Scanner = new Scanner()
}
diff --git a/sources/scala/tools/dtd2scala/Main.scala b/sources/scala/tools/dtd2scala/Main.scala
index 0771f59a85..ad2109148a 100644
--- a/sources/scala/tools/dtd2scala/Main.scala
+++ b/sources/scala/tools/dtd2scala/Main.scala
@@ -1,119 +1,93 @@
package scala.tools.dtd2scala ;
-
-import org.xml.sax.SAXParseException;
-import org.xml.sax.SAXException;
-import org.xml.sax.InputSource;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.{InputSource,SAXException,SAXParseException,XMLReader}
import org.xml.sax.helpers.XMLReaderFactory;
-import org.xml.sax.Attributes;
-import org.xml.sax.ext.DeclHandler;
import java.io.{File,FileWriter,PrintWriter,StringReader};
-import java.util.Map ;
-import java.util.HashMap ;
-import java.util.TreeMap ;
-import java.util.Iterator ;
-
object Main {
- // this implementation included in JDK1.4, but cannot resolve relative sysIDs
- final val DEFAULT_PARSER_NAME:String = "org.apache.crimson.parser.XMLReaderImpl" ;
-
- // DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser" ;
-
- final val DOC_WRAPPER_FRONT:String = "<!DOCTYPE doc SYSTEM \"";
- final val DOC_WRAPPER_BACK:String = "\"><doc></doc>";
-
- /** print usage string
- */
- def usage():Unit = {
- System.out.println("usage: dtd2scala [ -d <dir> ] <sysID> <object name>");
- System.out.println(" binds a DTD to class definitions");
- System.out.println(" will create a file [<dir>/]<object name>.scala");
- System.out.println("<dir> is the output directory [default is the path of <sysID>]");
- System.out.println("<sysID> is a system ID of an XML DTD");
- System.out.println("<object name> is the name of the resulting Scala source file ");
+ // included in JDK1.4, but cannot resolve relative sysIDs
+ final val DEFAULT_PARSER_NAME = "org.apache.crimson.parser.XMLReaderImpl" ;
+ // better "org.apache.xerces.parsers.SAXParser" ;
+
+ final val DECL_HANDLER = "http://xml.org/sax/properties/declaration-handler";
+
+ def printUsage:Unit = {
+ Console.println("usage: dtd2scala [ -d <dir> ] <sysID> <object name>");
+ Console.println(" binds a DTD to class definitions");
+ Console.println(" will create a file [<dir>/]<object name>.scala");
+ Console.println("<dir> is the output directory [path of <sysID> is default]");
+ Console.println("<sysID> is a system ID of an XML DTD");
+ Console.println("<object name> is the name of the resulting Scala source file ");
+ }
+
+ /** translates dtd to scala class definitions. see also printUsage */
+ def main(argv:Array[String]):Unit = {
+ import scala.Seq ; // to shadow case class Seq RegExp
+
+ new IterableArray( argv ) match {
+ case Seq( "-d", outdir, sysID, objName ) =>
+ continue( new File( outdir ), sysID, objName );
+ case Seq( "-sql", sysID ) => dosql( sysID );
+ case Seq( sysID, objName ) =>
+ continue( new File( sysID ).getParentFile(), sysID, objName );
+ case _ =>
+ { printUsage; System.exit(-1); }
+ }
+ }
+
+ private def continue( outdir:File, sysID:String, objName:String ) = {
+ val myH:MainHandler = new MainHandler();
+ parse( sysID, myH );
+ // myH.print(); // DEBUG
+
+ val p = new PrintWriter(new FileWriter(new File(outdir,
+ objName+".scala" )));
+ new DeclToScala( p, objName, myH.elemMap ).run;
+ }
+
+ private def dosql( sysID:String ) = {
+ val myH:MainHandler = new MainHandler();
+ parse( sysID, myH );
+ /*
+ val q = new PrintWriter(new FileWriter(new File(outdir,
+ objName+".sql" )));
+ */
+ val q = new PrintWriter(System.out);
+ new DeclToSQL( q, null:String, myH.elemMap ).run;
+ }
+
+
+ private def inputsrc( sysID:String ):InputSource = {
+ // create isrc for a fake doc referencing the DTD
+ val isrc:InputSource = new InputSource(
+ new StringReader("<!DOCTYPE doc SYSTEM \""+ sysID +"\"><doc></doc>")
+ );
+ val curDir:String = System.getProperty("user.dir");
+ isrc.setSystemId( "file:///"+curDir+"/fubar.xml" );
+ isrc;
+ }
+
+ private def parse( sysID:String, myH:MainHandler ) = {
+ val parser:XMLReader =
+ XMLReaderFactory.createXMLReader( DEFAULT_PARSER_NAME );
+
+ try { parser.setProperty( DECL_HANDLER, myH ); }
+ catch { case e:SAXException => e.printStackTrace(System.err); }
+
+ try { parser.parse( inputsrc( sysID )); }
+ catch {
+ case e:SAXParseException =>
+ System.err.println("SaxParseEx");e.printStackTrace( System.err );
+ case e:Exception => {
+ System.err.println("error: Parse error occurred - "+e.getMessage());
+ if( e.isInstanceOf[SAXException] )
+ e.asInstanceOf[SAXException].getException()
+ .printStackTrace( System.err )
+ else e.printStackTrace()
+ }
}
- /** main method. parses dtd of doc with <sysID> and translates to scala case
- * class definitions.
- * definitions are printed to stdout.
- * @argv two parameters, sysID and object name
- */
-
- def main(argv:Array[String]):Unit /*throws Exception*/ = {
-
- if ( argv.length == 0 ) {
- usage();
- System.exit(-1);
- }
-
- if(( argv.length != 2 )
- &&(( argv.length != 4 )
- ||(( argv.length == 4 )&&( !argv( 0 ).equals("-d"))))) {
- //System.out.println( argv.length+"ga"+argv[0].equals("-d") );
- usage();
- System.exit(-1);
- }
-
- val myH:MainHandler = new MainHandler();
- val sysID:String = argv( argv.length - 2 );
- val objname:String = argv( argv.length - 1 );
- var outdir:File = null.asInstanceOf[ File ];
- if ( argv.length == 4 ) {
- outdir = new File( argv( 1 ));
- } else {
- outdir = new File( sysID ).getParentFile();
- }
- val parser:XMLReader =
- XMLReaderFactory.createXMLReader( DEFAULT_PARSER_NAME );
-
- try {
- parser.setProperty("http://xml.org/sax/properties/declaration-handler", myH);
- }
- catch{
- case e:SAXException =>
- e.printStackTrace(System.err);
- }
- try {
- // create isrc for a fake doc referencing the DTD
- val isrc:InputSource = new InputSource(
- new StringReader( DOC_WRAPPER_FRONT
- + sysID
- + DOC_WRAPPER_BACK ) );
- val curDir:String = System.getProperty("user.dir");
- //String sysID2 = new File( sysID ).getAbsolutePath();
- //System.err.println( "file:///"+curDir+"/fubar.xml" );
- isrc.setSystemId( "file:///"+curDir+"/fubar.xml" );
- parser.parse( isrc );
- }
- catch {
- case e:SAXParseException =>
- System.err.println("SaxParseEx");
- e.printStackTrace( System.err );
- case e:Exception =>
- System.err.println("error: Parse error occurred - "+e.getMessage());
- if( e.isInstanceOf[SAXException] ) {
- e.asInstanceOf[SAXException].getException().printStackTrace(System.err)
- } else {
- e.printStackTrace()
- }
- }
-
- // myH.print(); // DEBUG
-
- // instantiate translator
- /* does not work due to backend handling of constructors, FIXME
- val translate:DeclToScala = new DeclToScala( outdir, objname );
- */
- val p = new PrintWriter( new FileWriter( new File( outdir, objname+".scala" )));
- val translate:DeclToScala = new DeclToScala( p, objname );
- // translate
- translate.toScala( myH.elemMap );
-
-
- } // main
-} //object main
+ }
+} //object main
diff --git a/sources/scala/tools/dtd2scala/MainHandler.scala b/sources/scala/tools/dtd2scala/MainHandler.scala
index 6bc5135dc3..595b98a34d 100644
--- a/sources/scala/tools/dtd2scala/MainHandler.scala
+++ b/sources/scala/tools/dtd2scala/MainHandler.scala
@@ -1,39 +1,21 @@
package scala.tools.dtd2scala ;
-//import org.xml.sax.SAXParseException;
-//import org.xml.sax.SAXException;
-//import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.Attributes;
import org.xml.sax.ext.DeclHandler;
-/*
-import java.util.Map ;
-import java.util.HashMap ;
-import java.util.TreeMap ;
-import java.util.Iterator ;
-*/
-//import scala.collection.Map ;
import scala.collection.mutable.HashMap ;
-/** 2 do :
- - handle modes of attributes (add #REQUIRED ones, fill in default of #IMPLIED)
- - allow package prefix to be given !
- - allow output directory to be given !
-*/
+// 2 do : - handle modes of attributes ( #REQUIRED, defaults for #IMPLIED )
+/** SAX handler, reacts to events during declaration parsing */
class MainHandler extends DefaultHandler with DeclHandler {
var elemMap:HashMap[String,ElemDecl] = new HashMap[String,ElemDecl];
- // DTDHandler methods
-
- /** encountered element declaration
- */
- def elementDecl( name:String, contentModel:String ):Unit
- /* throws SAXException */ = {
+ // zzz DTDHandler methods zzz
+ /** encountered element declaration */
+ def elementDecl( name:String, contentModel:String ) = {
elemMap.get( name ).match {
-
case Some(decl) => // was added because of ATTLIST decl before
elemMap.update( name, ElemDecl( decl.name,
contentModel,
@@ -45,70 +27,31 @@ class MainHandler extends DefaultHandler with DeclHandler {
}
} // elementDecl(String,String)
- /** encountered attribute declaration.
- */
+ /** encountered attribute declaration. */
def attributeDecl(elementName:String,
attributeName:String,
tpe:String,
valueDefault:String,
- value:String ) /*throws SAXException*/ = {
-
- var attribs:HashMap[String,AttrDecl] =
- elemMap.get( elementName ).match {
- case None =>
- val amap = new HashMap[String,AttrDecl];
- elemMap.update( elementName,
- ElemDecl( elementName,
- null:String,
- amap ));
- amap;
-
- case Some(decl) =>
- decl.attribs;
+ value:String ) = {
+
+ val attribs = elemMap.get( elementName ).match {
+ case None => { val amap = new HashMap[String,AttrDecl];
+ elemMap.update( elementName,
+ ElemDecl( elementName,
+ null:String,
+ amap ));
+ amap; }
+ case Some(decl) => decl.attribs;
};
attribs.update( attributeName, AttrDecl(attributeName, tpe ));
} // attributeDecl(String,String,String,String,String)
- /** Internal entity declaration.
- */
- def internalEntityDecl( name:String, text:String ):Unit
- /*throws SAXException*/ = {
- // ignore
- }
-
- /** External entity declaration.
- */
- def externalEntityDecl( name:String,
- publicId:String ,
- systemId:String ):Unit
- /*throws SAXException*/ = {
- // ignore
- }
-
- /*
-
- // for debugging
+ /** Internal entity declaration. */
+ def internalEntityDecl( name:String, text:String ) = {/*ignored*/}
- public void print() {
- for(Iterator it = elemMap.keySet().iterator(); it.hasNext(); ) {
- ElemDecl decl = (ElemDecl) elemMap.get( it.next() );
- System.out.print(decl.name);
- AttrDecl adecl = null;
- System.out.print("{");
- for(Iterator it2 = decl.attribs.keySet().iterator();
- it2.hasNext(); ) {
- if(adecl != null)
- System.out.print(",");
- adecl = (AttrDecl) decl.attribs.get( it2.next() );
- System.out.print(adecl.name+":"+adecl.type);
- }
- System.out.println("}");
- }
-
-
- }
- */
+ /** External entity declaration. */
+ def externalEntityDecl(name:String,pubId:String,sysId:String)= {/*ignored*/}
} // class MyDTDHandler
diff --git a/sources/scala/tools/dtd2scala/XMLDecl.scala b/sources/scala/tools/dtd2scala/XMLDecl.scala
index 31c861fbf8..50edccf8a0 100644
--- a/sources/scala/tools/dtd2scala/XMLDecl.scala
+++ b/sources/scala/tools/dtd2scala/XMLDecl.scala
@@ -7,9 +7,11 @@ abstract class XMLDecl ;
case class ElemDecl( name:String ,
contentModel:String ,
attribs:HashMap[String,AttrDecl] )
- extends XMLDecl; /*AttrDecl[]*/
+ extends XMLDecl {
+
+ def containsText = contentModel.indexOf("#PCDATA") != -1 ;
+}; /*AttrDecl[]*/
// ignore default values 4 now
case class AttrDecl( name:String,
tpe:String ) extends XMLDecl;
-
diff --git a/sources/scala/tools/dtd2scala/regexp/Alt.scala b/sources/scala/tools/dtd2scala/regexp/Alt.scala
new file mode 100644
index 0000000000..fc88e9b8e0
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/Alt.scala
@@ -0,0 +1,4 @@
+package scala.tools.dtd2scala.regexp ;
+
+case class Alt(rs:RegExp*) extends RegExp;
+
diff --git a/sources/scala/tools/dtd2scala/regexp/Eps.scala b/sources/scala/tools/dtd2scala/regexp/Eps.scala
new file mode 100644
index 0000000000..0c0079745b
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/Eps.scala
@@ -0,0 +1,3 @@
+package scala.tools.dtd2scala.regexp ;
+
+case object Eps extends RegExp;
diff --git a/sources/scala/tools/dtd2scala/regexp/Node.scala b/sources/scala/tools/dtd2scala/regexp/Node.scala
new file mode 100644
index 0000000000..c56b60925d
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/Node.scala
@@ -0,0 +1,3 @@
+package scala.tools.dtd2scala.regexp ;
+
+case class Node(name:String) extends RegExp;
diff --git a/sources/scala/tools/dtd2scala/regexp/PCDATA_.scala b/sources/scala/tools/dtd2scala/regexp/PCDATA_.scala
new file mode 100644
index 0000000000..5483fda9da
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/PCDATA_.scala
@@ -0,0 +1,3 @@
+package scala.tools.dtd2scala.regexp ;
+
+case object PCDATA_ extends RegExp ;
diff --git a/sources/scala/tools/dtd2scala/regexp/Parser.scala b/sources/scala/tools/dtd2scala/regexp/Parser.scala
new file mode 100644
index 0000000000..dc55ff39d2
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/Parser.scala
@@ -0,0 +1,64 @@
+package scala.tools.dtd2scala.regexp ;
+
+/** Parser for regexps (content models in DTD element declarations) */
+
+object Parser with Scanner { // a bit too permissive concerning #PCDATA
+
+ /** parses the argument to a regexp */
+ def parse(s:String):RegExp = { initScanner( s ); regexp }
+
+ // zzz parser methods zzz
+ private def accept( tok:int ) = {
+ if( token != tok ) error("unexpected token:"+token2string(token));
+ nextToken
+ }
+
+ private def suffix = (token==STAR)||(token==PLUS)||(token==OPT);
+
+ private def handleSuffix(s:RegExp) = {
+ if( token == STAR ) { nextToken; Star( s ) }
+ else if( token == PLUS ){ nextToken; Seq( s, Star( s )) }
+ else if( token == OPT ) { nextToken; Alt( Eps, s ); }
+ else { error("suffix expected"); PCDATA_ }
+ }
+
+ private def maybeSuffix(s:RegExp) = if( suffix ) handleSuffix( s ) else s;
+
+ // regexp ::= seq [ '+' | '*' | '?' ]
+ private def regexp:RegExp = maybeSuffix( seq );
+
+ // seq ::= factor { ',' factor }
+ private def seq = {
+ val f = factor;
+ if( token != COMMA ) f else {
+ var fs:List[ RegExp ] = List( f );
+ while( token == COMMA ) { nextToken; fs = factor :: fs }
+ Seq( fs.reverse:_* );
+ }
+ }
+
+ // factor ::= atomSuffix { '|' atomSuffix }
+ private def factor:RegExp = {
+ var a = atomSuffix;
+ if( token != CHOICE ) a else {
+ var as:List[ RegExp ] = List( a );
+ while( token == CHOICE ) { nextToken; as = atomSuffix :: as; }
+ Alt( as.reverse:_* );
+ }
+ }
+
+ // atomSuffix ::= atom [ '+' | '*' | '?' ]
+ private def atomSuffix = maybeSuffix( atom );
+
+ // atom ::= '(' regexp ')'
+ // | '#PCDATA'
+ // | node
+ // | END
+ private def atom =
+ if( token == LPAREN ) { nextToken; val a = regexp; accept( RPAREN ); a }
+ else if( token == PCD ) { nextToken; PCDATA_ }
+ else if( token == NODE ){ val a = Node( value ); nextToken; a }
+ else if( token == END ) { Eps }
+ else error("unexpected token:"+token2string( token ));
+
+}
diff --git a/sources/scala/tools/dtd2scala/regexp/RegExp.scala b/sources/scala/tools/dtd2scala/regexp/RegExp.scala
new file mode 100644
index 0000000000..e5c12ac588
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/RegExp.scala
@@ -0,0 +1,15 @@
+package scala.tools.dtd2scala.regexp ;
+
+abstract class RegExp ;
+
+//case class Node(name:String) extends RegExp;
+//case object PCDATA_ extends RegExp ;
+
+//case object Eps extends RegExp;
+//case class Star(r:RegExp) extends RegExp;
+//case class Seq(rs:RegExp*) extends RegExp;
+//case class Alt(rs:RegExp*) extends RegExp;
+
+object RegExp {
+ def parse(s:String):RegExp = Parser.parse( s );
+}
diff --git a/sources/scala/tools/dtd2scala/regexp/Scanner.scala b/sources/scala/tools/dtd2scala/regexp/Scanner.scala
new file mode 100644
index 0000000000..eca36fab12
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/Scanner.scala
@@ -0,0 +1,59 @@
+package scala.tools.dtd2scala.regexp ;
+
+/** Scanner for regexps (content models in DTD element declarations) */
+class Scanner with Tokens {
+
+ // zzz constants zzz
+ private val ENDCH:char = '%';
+
+ // zzz fields zzz
+ var token:int = 0;
+ var value:String = "";
+
+ private var it:Iterator[char] = null;
+ private var c:char = 'z';
+
+
+ /** initializes the scanner on input s */
+ def initScanner( s:String ) = {
+ it = new IterableString( s ).elements ;
+ next;
+ token = 0;
+ nextToken;
+ }
+
+ /** scans the next token */
+ def nextToken = { token = if( token != END ) readToken else END }
+
+ // zzz scanner methods zzz
+
+ // todo: see XML specification... probably isLetter,isDigit is fine
+ private def isIdentChar = { ('a' <= c && c <= 'z')
+ || ('A' <= c && c <= 'Z')};
+
+ private def next = if( it.hasNext ) c = it.next else c = ENDCH;
+
+ private def skip( i:int ):Unit = if( i > 0 ) { next; skip(i-1) } else { }
+
+ private def readToken:int = c.match {
+ case '(' => next; LPAREN;
+ case ')' => next; RPAREN;
+ case ',' => next; COMMA;
+ case '*' => next; STAR;
+ case '+' => next; PLUS;
+ case '?' => next; OPT;
+ case '|' => next; CHOICE;
+ case '#' => skip( "PCDATA".length() ); next; PCD
+ case '%' => END;
+ case _ => if( isIdentChar )
+ { readValue; NODE }
+ else
+ { error("unexpected character:"+c); END }
+ }
+
+ private def readValue = {
+ var buf = List( c ); next; while ( isIdentChar ) { buf = c::buf; next }
+ value = buf.foldLeft ("") { ( s, c ) => c+s };
+ }
+
+}
diff --git a/sources/scala/tools/dtd2scala/regexp/Seq.scala b/sources/scala/tools/dtd2scala/regexp/Seq.scala
new file mode 100644
index 0000000000..f2658f7c20
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/Seq.scala
@@ -0,0 +1,3 @@
+package scala.tools.dtd2scala.regexp ;
+
+case class Seq(rs:RegExp*) extends RegExp;
diff --git a/sources/scala/tools/dtd2scala/regexp/Star.scala b/sources/scala/tools/dtd2scala/regexp/Star.scala
new file mode 100644
index 0000000000..8927ff70e9
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/Star.scala
@@ -0,0 +1,3 @@
+package scala.tools.dtd2scala.regexp ;
+
+case class Star(r:RegExp) extends RegExp;
diff --git a/sources/scala/tools/dtd2scala/regexp/Tokens.scala b/sources/scala/tools/dtd2scala/regexp/Tokens.scala
new file mode 100644
index 0000000000..2cc704a4f4
--- /dev/null
+++ b/sources/scala/tools/dtd2scala/regexp/Tokens.scala
@@ -0,0 +1,32 @@
+package scala.tools.dtd2scala.regexp ;
+
+class Tokens {
+
+ // Tokens
+
+ val PCD = 0;
+ val NODE = 1;
+ val EMPTY = 2;
+ val LPAREN = 3;
+ val RPAREN = 4;
+ val COMMA = 5;
+ val STAR = 6;
+ val PLUS = 7;
+ val OPT = 8;
+ val CHOICE = 9;
+ val END = 10;
+
+ def token2string( i:int ):String = i.match {
+ case 0 => "#PCD";
+ case 1 => "NODE";
+ case 2 => "EMPTY";
+ case 3 => "(";
+ case 4 => ")";
+ case 5 => ",";
+ case 6 => "*";
+ case 7 => "+";
+ case 8 => "?";
+ case 9 => "|";
+ case 10 => "END";
+ }
+}