diff options
author | buraq <buraq@epfl.ch> | 2003-11-03 15:20:13 +0000 |
---|---|---|
committer | buraq <buraq@epfl.ch> | 2003-11-03 15:20:13 +0000 |
commit | 33d19305e4e00a38a167d3e159e92d90cd4de7ce (patch) | |
tree | 1546cf70dd7e06f1de1b9aae6bf346fdb8c14244 /sources | |
parent | f2edc84853de62dbf63c9c1cda34d06e153ce88c (diff) | |
download | scala-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.scala | 75 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/DeclToScala.scala | 110 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/Main.scala | 192 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/MainHandler.scala | 97 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/XMLDecl.scala | 6 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/Alt.scala | 4 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/Eps.scala | 3 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/Node.scala | 3 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/PCDATA_.scala | 3 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/Parser.scala | 64 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/RegExp.scala | 15 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/Scanner.scala | 59 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/Seq.scala | 3 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/Star.scala | 3 | ||||
-rw-r--r-- | sources/scala/tools/dtd2scala/regexp/Tokens.scala | 32 |
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"; + } +} |