diff options
author | buraq <buraq@epfl.ch> | 2003-06-19 17:15:34 +0000 |
---|---|---|
committer | buraq <buraq@epfl.ch> | 2003-06-19 17:15:34 +0000 |
commit | 88cb90bf6d10e0766c08cfa277e32a52de6f96ab (patch) | |
tree | 7ce6cfd1b271387904fdb68b6a9928768ac26403 | |
parent | e7609c9d0e314117ef1c6161827d0982076090e7 (diff) | |
download | scala-88cb90bf6d10e0766c08cfa277e32a52de6f96ab.tar.gz scala-88cb90bf6d10e0766c08cfa277e32a52de6f96ab.tar.bz2 scala-88cb90bf6d10e0766c08cfa277e32a52de6f96ab.zip |
automata stuff for pattern matching
-rw-r--r-- | sources/scalac/transformer/matching/BerrySethi.java | 642 | ||||
-rw-r--r-- | sources/scalac/transformer/matching/DetWordAutom.java | 892 | ||||
-rw-r--r-- | sources/scalac/transformer/matching/FiniteAutom.java | 120 | ||||
-rw-r--r-- | sources/scalac/transformer/matching/Label.java | 120 | ||||
-rw-r--r-- | sources/scalac/transformer/matching/NondetWordAutom.java | 409 | ||||
-rw-r--r-- | sources/scalac/transformer/matching/StateSetComparator.java | 34 |
6 files changed, 2217 insertions, 0 deletions
diff --git a/sources/scalac/transformer/matching/BerrySethi.java b/sources/scalac/transformer/matching/BerrySethi.java new file mode 100644 index 0000000000..e502c75c7c --- /dev/null +++ b/sources/scalac/transformer/matching/BerrySethi.java @@ -0,0 +1,642 @@ +package scalac.transformer.matching ; + +import scalac.ApplicationError ; +import scalac.ast.Tree ; +import scalac.util.Name ; +import Tree.* ; + +import java.util.* ; + +//import scala.compiler.printer.TextTreePrinter ; +//import scala.compiler.printer.XMLAutomPrinter ; + +/** a Berry-Sethi style construction for nfas. + * this class plays is the "Builder" for the "Director" class WordRecognizer. + */ + +class BerrySethi { + + boolean isStar( Name n ) { + String s = n.toString(); + return (s.indexOf("$") != -1) + &&(!s.startsWith("nest")); + } + + + HashSet labels; + + int pos; + // maps a literal pattern to an Integer ( the position ) + // is not *really* needed (postfix order determines position!) + HashMap posMap; // pos: Patterns -> Positions + // don't let this fool you, only labelAt is a real, surjective mapping + HashMap labelAt; // chi: Positions -> Obj + + TreeSet globalFirst; + + // results which hold all info for the NondetWordAutomaton + + HashMap follow; // follow: Positions -> Set[Positions] + + + // Unit test ? + boolean nullable( Tree pat ) { + //System.out.print("<nullable>"); + //DEBUG.print( pat ); + //System.out.println("</nullable>"); + switch( pat ) { + case Apply(_, _): + return false; + case Sequence( Tree[] trees ): + return trees.length == 0; + case Subsequence( Tree[] trees ): + return nullable( trees ); + case Bind(Name n, Tree t): + /* + if( isStar( n ) ) // generated for star/plus(?) + return true; + */ + return nullable( t ); + case Alternative(Tree[] choices): + boolean result = false; + for( int i = 0; i < choices.length && !result; i++ ) + result = result || nullable( choices[ i ] ); + return result; + default: + return false; + + } + } + + + /** returns true if a Sequence pattern matches the empty sequence + * @param pat the sequence pattern. + */ + boolean nullableSequence( Tree pat ) { + switch( pat ) { + case Sequence( Tree[] pats ): + return nullable( pats ); + } + return false; + } + + /** returns true if a sequence of patterns (usually children of a + * sequence or subsequence node) is nullable. + * @param pats the sequence of patterns + */ + boolean nullable( Tree[] pats ) { + boolean result = true; + for( int i = 0; i < pats.length && result; i++ ) + result = result && nullable( pats[ i ] ); + return result; + } + + /** computes first( alpha ) where alpha is a word regexp + */ + + TreeSet compFirst( Tree pat ) { + //System.out.print("<compFirst>"); + //DEBUG.print( pat ); + //System.out.println("</compFirst>"); + switch( pat ) { + case Sequence( _ ): + case Typed(_,_): + case Select(_,_): + case Apply(_, _): + TreeSet tmp = new TreeSet(); + tmp.add( (Integer) posMap.get( pat )); // singleton set + return tmp; + case Literal( _ ): + TreeSet tmp = new TreeSet(); + tmp.add( (Integer) posMap.get( pat )); // singleton set + return tmp; + case Subsequence( Tree[] trees ): + return compFirst( trees ); + case Alternative( Tree[] trees ): + TreeSet tmp = new TreeSet(); + for( int i = 0; i < trees.length; i++ ) { + tmp.addAll( compFirst( trees[ i ] )); + } + return tmp; + case Bind( _, Tree tree ): + return compFirst( tree ); + case Ident( Name name ): + //if( name != Name.fromString("_") ) + // throw new ApplicationError("unexpected pattern"); + TreeSet tmp = new TreeSet(); + tmp.add( (Integer) posMap.get( pat )); // singleton set + return tmp; + default: + throw new ApplicationError("unexpected pattern"); + } + } + + + + /** computes last( alpha ) where alpha is a word regexp + */ + TreeSet compLast( Tree pat ) { + //System.out.print("<last>"); + //DEBUG.print( pat ); + //System.out.println("</compLast>"); + switch( pat ) { + case Sequence( _ ): + case Apply(_, _): + TreeSet tmp = new TreeSet(); + tmp.add( (Integer) posMap.get( pat )); // singleton set + return tmp; + case Literal( _ ): + TreeSet tmp = new TreeSet(); + tmp.add( (Integer) posMap.get( pat )); // singleton set + return tmp; + case Subsequence( Tree[] trees ): + return compLast( trees ); + case Alternative( Tree[] trees ): + TreeSet tmp = new TreeSet(); + for( int i = 0; i < trees.length; i++ ) { + tmp.addAll( compLast( trees )); + } + return tmp; + case Bind( _, Tree tree ): + return compLast( tree ); + default: + throw new ApplicationError("unexpected pattern"); + } + } + + + /** computes first(w) where w=alpha_1...alpha_n are successors of a + * sequence node + */ + TreeSet compFirst( Tree[] pats ) { + if( pats.length == 0 ) + return new TreeSet(); + + int i = 0; + Tree tmp = pats[ i ]; + TreeSet result = compFirst( tmp ); + i++; + while( nullable(tmp) && (i < pats.length )) { + tmp = pats[ i ]; + result.addAll( compFirst( tmp )); + i++; + } + return result; + } + + // Unit test ? + + /** computes last(w) where w are successors of a sequence node + */ + TreeSet compLast( Tree[] pats ) { + /* + System.out.print("<last>"); + for( int k = 0; k<pats.length; k++) { + DEBUG.print( pats[k] ); + System.out.print(" "); + } + System.out.println(); + */ + if( pats.length == 0 ) + return new TreeSet(); + + int i = pats.length - 1; + Tree tmp = pats[ i ]; + TreeSet result = compLast( tmp ); + i--; + while( nullable(tmp) && (i >= 0 )) { + tmp = pats[ i ]; + result.addAll( compLast( tmp )); + i++; + } + return result; + } + + // starts from the right-to-left + // precondition: pos is final + // pats are successor patterns of a Sequence node + TreeSet compFollow(Tree[] pats) { + TreeSet first = null; + this.recVars = new HashMap(); + TreeSet fol = new TreeSet(); + if( pats.length > 0 ) {//non-empty expr + int i = pats.length; + fol.add( new Integer( pos )); // don't modify pos ! + do { + --i; + first = compFollow1( fol, pats[ i ] ); + if( nullable( pats[ i ] )) + fol.addAll( first ); + else + fol = first; + //System.out.println("in compFollow: first"+first); + //System.out.println("in compFollow: fol"+fol); + + } while( i > 0 ); + } + if( null == first ) + first = new TreeSet(); + else { + first = fol; + } + this.follow.put(new Integer( 0 ), first); + return first; + } + + HashMap recVars; + + /** returns the first set of an expression, setting the follow set along + * the way + */ + TreeSet compFollow1( TreeSet fol, Tree pat ) { + switch( pat ) { + case Subsequence(Tree[] trees): + TreeSet first = null; + int i = trees.length; + if( i > 0 ) { // is nonempty + do { + --i; + first = compFollow1(fol, trees[ i ]); + if( nullable( trees[ i ] )) + fol.addAll( first ); + else + fol = first; + } while( i > 0 ) ; + } + if( null == first ) first = new TreeSet(); + return first; + case Alternative(Tree[] choices): + TreeSet first = new TreeSet(); + for( int i = choices.length - 1; i >= 0; --i ) { + first.addAll( compFollow1( fol, choices[ i ] )); + } + return first; + + case Bind( Name n, Tree t ): + + Integer p = (Integer) this.posMap.get( pat ); + + TreeSet first = compFirst( t ); + //System.out.print("BIND" + first); + recVars.put( pat.symbol(), first ); + + // if( appearsRightmost( n, t )) + // follow = oldfollw + ownfirst + if( isStar( n ) ) + fol.addAll( first ); // an iterated pattern + + this.follow.put( p, fol.clone() ); + //System.out.println("Bind("+n+",...) first:"+first); + //System.out.println("Bind("+n+",...) follow:"+fol); + + // continue to compute follow sets with adjusted fol + return compFollow1( fol, t ); + + case Ident( Name n ): + if ((pat.symbol() != null ) + && pat.symbol().isPrimaryConstructor()) { + // same as Apply + Integer pos = (Integer) this.posMap.get( pat ); + TreeSet tset = (TreeSet) fol.clone(); + this.follow.put( pos, tset ); + TreeSet first = new TreeSet(); + first.add( pos ); + return first; + } + + if ( recVars.keySet().contains( pat.symbol() )) { // grammar + TreeSet first = (TreeSet) recVars.get( pat.symbol() ); + TreeSet follow = ((TreeSet) fol.clone()); + first.addAll( follow ); + //recVars.put//this.follow.put( pat.symbol(), follow ); + return first; + } + + // --- --- only happens when called from BindingBerrySethi + // [... x ...] changed to [... x@_ ...] + + // non-generated, non-recursive variable should not appear, + // so this is a wildcard pattern _ + + Integer pos = (Integer) this.posMap.get( pat ); + TreeSet tset = (TreeSet) fol.clone(); + this.follow.put( pos, tset ); + TreeSet first = new TreeSet(); + first.add( pos ); + //System.out.println("Ident("+n+",...) first:"+first); + //System.out.println("Ident("+n+",...) follow:"+tset); + return first; + + case Sequence( _ ): + case Apply(_, _): + case Literal( _ ): + case Typed(_,_): + case Select(_,_): + Integer pos = (Integer) this.posMap.get( pat ); + TreeSet tset = (TreeSet) fol.clone(); + this.follow.put( pos, tset ); + TreeSet first = new TreeSet(); + first.add( pos ); + return first; + default: + throw new ApplicationError("unexpected pattern: "+pat.getClass()); + } + } + + /** called at the leaves of the regexp + */ + void seenLabel( Tree pat, Integer i, Label label ) { + this.posMap.put( pat, i ); + this.labelAt.put( i, label ); + if( label != Label.DefaultLabel ) + this.labels.add( label ); + } + + /** overriden in BindingBerrySethi + */ + void seenLabel( Tree pat, Label label ) { + seenLabel( pat, new Integer( ++pos ), label ); + } + + /** returns "Sethi-length" of a pattern, creating the set of position + * along the way + */ + + Vector activeBinders; + + // todo: replace global variable pos with acc + void traverse( Tree pat ) { + switch( pat ) { + + // (is tree automaton stuff, more than Berry-Sethi) + case Sequence( _ ): + case Apply( _, _ ): + case Typed( _, _ ): + case Select( _, _ ): + Label label = new Label.TreeLabel( pat ); + seenLabel( pat, label ) ; + + return ; + + case Literal( Object val ): + Label label = new Label.SimpleLabel( (Literal) pat ); + seenLabel( pat, label ) ; + + return ; + + case Subsequence( Tree[] trees ): + for( int i = 0; i < trees.length; i++ ) { + traverse( trees[ i ] ); + } + return ; + case Alternative(Tree[] choices): + for( int i = 0; i < choices.length; i++ ) { + traverse( choices[ i ] ); + } + return ; + case Bind(Name name, Tree body): + recVars.put( pat.symbol(), Boolean.TRUE ); + if( !isStar( name ) ) + { + activeBinders.add( pat.symbol() ); + traverse( body ); + activeBinders.remove( pat.symbol() ); + } + else + traverse( body ); + return ; + + case Ident(Name name): + if ((pat.symbol() != null ) + && pat.symbol().isPrimaryConstructor()) { + // same as Apply + Label label = new Label.TreeLabel( pat ); + seenLabel( pat, label ) ; + + return ; + } + + + if( recVars.get( pat.symbol() ) != null ) { + return ; + } + // _ and variable x ( == x @ _ ) + Label label = Label.DefaultLabel; + seenLabel( pat, label ); + + return ; + + //else throw new ApplicationError("cannot handle this: "+name); + // case Apply( _, _ ): + //throw new ApplicationError("cannot handle this"); + default: + throw new ApplicationError("this is not a pattern"); + } + } + + + TreeMap finals; // final states + + //TreeSet initialsRev; // final states + + HashMap deltaq[]; // delta + + + + Vector defaultq[]; // default transitions + + + //HashMap deltaqRev[]; // delta of Rev + //Vector defaultqRev[]; // default transitions of Rev + + + protected void makeTransition( Integer srcI, Integer destI, Label label ) { + int src = srcI.intValue() ; + int dest = destI.intValue() ; + Vector arrows; //, revArrows; + //Label revLabel = new Label.Pair( srcI, label ); + switch( label ) { + case DefaultLabel: + arrows = defaultq[ src ]; + //revArrows = defaultqRev[ dest ]; + break; + default: + arrows = (Vector) deltaq[ src ].get( label ); + if( arrows == null ) + deltaq[ src ].put( label, + arrows = new Vector() ); + /* + revArrows = (Vector) deltaqRev[ dest ].get( revLabel ); + if( revArrows == null ) + deltaqRev[ dest ].put( revLabel, + revArrows = new Vector() ); + */ + } + arrows.add( destI ); + //revArrows.add( srcI ); + } + + + TreeSet initials; + //NondetWordAutom revNfa ; + + protected void initialize( Tree[] subexpr ) { + this.posMap = new HashMap(); + this.labelAt = new HashMap(); + + + this.follow = new HashMap(); + this.labels = new HashSet(); + this.recVars = new HashMap(); + this.pos = 0; + // determine "Sethi-length" of the regexp + activeBinders = new Vector(); + for( int i = 0; i < subexpr.length; i++ ) { + traverse( subexpr[ i ] ); + assert ( activeBinders.isEmpty() ); + } + + this.initials = new TreeSet(); + initials.add( new Integer( 0 )); + + } + + protected void initializeAutom() { + + finals = new TreeMap(); // final states + deltaq = new HashMap[ pos ]; // delta + defaultq = new Vector[ pos ]; // default transitions + + for( int j = 0; j < pos; j++ ) { + deltaq[ j ] = new HashMap(); + defaultq[ j ] = new Vector(); + } + } + + void collectTransitions() { // make transitions + + for( int j = 0; j < pos; j++ ) { + + Integer q = new Integer( j ); + + //System.out.print( "--q="+q ); + //System.out.println(" labelAt:"+labelAt.get( q )); + + TreeSet fol = (TreeSet) this.follow.get( q ); + //assert fol != null; + for( Iterator it = fol.iterator(); it.hasNext(); ) { + Integer p = (Integer) it.next(); + //System.out.println( "-- -- p="+p ); + if( p.intValue() == pos ) { + finals.put( q, finalTag ); + } else { + makeTransition( new Integer(j), p, + (Label) labelAt.get( p )); + } + } + } + + } + + Integer finalTag; + + public NondetWordAutom automatonFrom( Tree pat, Integer finalTag ) { + + this.finalTag = finalTag; + + //System.out.println( "enter automatonFrom(...)"); // UNIT TEST + //System.out.println( TextTreePrinter.toString(pat) ); + /*DEBUG = new TextTreePrinter( System.out ); + DEBUG.begin(); + DEBUG.print( pat ); + DEBUG.end(); + */ + //System.out.println( nullableSequence( pat )); // UNIT TEST + switch( pat ) { + case Sequence( Tree[] subexpr ): + initialize( subexpr ); + + + // (1) compute first + + //globalFirst = compFirst( subexpr ); + //System.out.println(globalFirst); + + // (2) compute follow; + ++pos; + //Set ignore = compFollow( subexpr ); + //System.out.println(ignore); + //System.exit(0); + //assert (ignore.equals( globalFirst )); + + globalFirst = compFollow( subexpr ); + + //System.out.print("someFirst:");debugPrint(someFirst); + + // construct the automaton's explicit representation + + initializeAutom(); + + + // defaultqRev = new Vector[ pos ]; // default transitions + + collectTransitions(); + + + //TreeSet initials = new TreeSet(); + //initials.add( new Integer( 0 ) ); + + NondetWordAutom result = + new NondetWordAutom(pos, // = nstates + labels, + initials, + finals, + (Object) deltaq, + (Object) defaultq, + null/*(Object) qbinders*/); + + /* + System.out.println("inBerrySethi"); + XMLAutomPrinter pr = new XMLAutomPrinter( System.out ); + pr.begin(); + pr.print( result ); + pr.print( revNfa ); + pr.end(); + System.out.println("initialsRev = "+initialsRev); + System.out.println("outBerrySethi"); + */ + //System.exit(0); + return result; //print(); + } + + throw new ApplicationError("expected a sequence pattern"); + } + + void print1() { + System.out.println("after sethi-style processing"); + System.out.println("#positions:" + pos); + System.out.println("posMap:"); + + for( Iterator it = this.posMap.keySet().iterator(); + it.hasNext(); ) { + Tree t = (Tree) it.next(); + switch(t) { + case Literal( Object value ): + System.out.print( "(" + t.toString() + " -> "); + String s2 = ((Integer) posMap.get(t)).toString(); + System.out.print( s2 +") "); + } + } + System.out.println("\nfollow: "); + for( int j = 1; j < pos; j++ ) { + TreeSet fol = (TreeSet) this.follow.get(new Integer(j)); + System.out.print("("+j+" -> "+fol.toString()+") "); + //debugPrint( fol ); + System.out.println(); + } + + } + + + +} diff --git a/sources/scalac/transformer/matching/DetWordAutom.java b/sources/scalac/transformer/matching/DetWordAutom.java new file mode 100644 index 0000000000..1f81e8c04d --- /dev/null +++ b/sources/scalac/transformer/matching/DetWordAutom.java @@ -0,0 +1,892 @@ +package scalac.transformer.matching ; + +import scalac.ast.Tree ; +import Tree.* ; + +import java.util.* ; + +import scalac.ApplicationError ; + +public class DetWordAutom extends FiniteAutom { + + static final int FIRST = 0; + static final int LAST = FIRST + 1; + + static final int WHICH_LONGEST_MATCH = FIRST ; + + // inherited from FiniteAutom: + + // int nstates; // number of states + // HashSet labels;// the alphabet + // TreeMap finals; + + // HashMap deltaq[]; + //Integer defaultq[]; + + + // used only during determinization and debug printing + // Q -> (Label -> Q ) + HashMap delta; + // Q -> Integer; + HashMap indexMap; + + // Integer -> Q + HashMap invIndexMap; + + // only not null if this is a right-transducer + public Vector qbinders[]; + + final static Integer NODEFAULT = new Integer( -1 ); + + public boolean isSink( int i ) { + return (((HashMap[])deltaq)[ i ].keySet().isEmpty() + && (defaultq != null ) + && (((Integer)defaultq( i )).intValue() == i)); + } + + public boolean hasDefault( int i ) { + return (Integer) defaultq( i ) != NODEFAULT; + } + + void determinize( NondetWordAutom nfa ) { + //System.out.println("DetWordAutom:determinize"); + //System.out.println("nfa:");nfa.print(); + TreeSet states;// temp: Set[Set[Integer]] + HashMap deftrans; // Set[Integer] -> Int + + HashMap trans; // always points to a mapping ( Label -> Q ) + int ix = 0; // state index + + this.labels = nfa.labels; + ////System.out.println("Labels: "+labels); + this.delta = new HashMap(); + //this.dead = -1; + + states = new TreeSet( new StateSetComparator() ); + deftrans = new HashMap(); + // temporarily: Map[Set[Integer]] later: Map[Integer] + this.finals = new TreeMap( new StateSetComparator() ); + this.invIndexMap = new HashMap(); + this.indexMap = new HashMap(); + + // new initial state (singleton set { q0 } by construction) + + TreeSet q0 = new TreeSet(); + q0.addAll( nfa.initials ); /*new Integer( 0 )); */ + states.add( q0 ); + + TreeSet empty = new TreeSet(); + deftrans.put( q0, empty ); + states.add( empty ); + deftrans.put( empty, empty ); + + Stack rest = new Stack(); + if( nfa.isFinal( 0 ) ) + this.finals.put( q0, nfa.finalTag( 0 ) ); + + + rest.push( empty ); + rest.push( q0 ); + while( !rest.empty() ) { + TreeSet P1 = (TreeSet) rest.pop(); + + //System.out.println("states:"+ states); + //System.out.println("P1:"+ P1); + + invIndexMap.put( new Integer( ix ), P1 ); + indexMap.put( P1, new Integer( ix++ )); + delta.put( P1, trans = new HashMap()); + + // labelled transitions + + for( Iterator it = labels.iterator(); it.hasNext(); ) { + Object label = it.next(); + ////System.out.print( "Label: " + label +" "); + // Qdest will contain all states reachable via `label' + // from some nfa state in P1; + TreeSet Qdest = nfa.getSide( P1, label ); + //System.out.println("Qdest:"+Qdest); + if( !states.contains( Qdest ) ) { + states.add( Qdest ); + ////System.out.print(" (added)" ); + rest.push( Qdest ); + ////System.out.print(" (pushed)"); + + if( nfa.containsFinal( Qdest ) ) + this.finals.put( Qdest, nfa.finalTag( Qdest )); + ////System.out.print(" (added final)"); + + } + ////System.out.println(".Qdest"); + + trans.put( label, Qdest ); + // //System.out.println( "Qdest: " + Qdest); + + } + + // default transitions + + TreeSet defTarget = (TreeSet) nfa.defaultq( P1 ); + //System.out.println("defTarget:"+defTarget); + deftrans.put( P1, defTarget ); + + if( !states.contains( defTarget ) ) { + states.add( defTarget ); + rest.push( defTarget ); + if( nfa.containsFinal( defTarget ) ) + this.finals.put( defTarget, nfa.finalTag( defTarget )); + } + } + + // <DEBUG> + // printBefore( states, deftrans ); + + // </DEBUG> do not call printBefore after this point + // //System.out.println("indexMap: "+indexMap); + + this.nstates = states.size(); + deltaq = new HashMap[ nstates ]; + defaultq = new Integer[ nstates ]; + + // we replace Set[Set[Integer]] by its index and clean up + + for( Iterator it = states.iterator(); it.hasNext(); ) { + TreeSet state = (TreeSet) it.next(); + Integer state_x = (Integer) indexMap.get( state ); + + TreeSet defTarget = (TreeSet) deftrans.get( state ); + Integer defTarget_x; + if( defTarget != null ) { + defTarget_x = (Integer) indexMap.get( defTarget ); + ////System.out.println("deftarget" + defTarget); + } else + defTarget_x = NODEFAULT; + + ////System.out.print(state.toString() + " --> " + state_x); + //System.out.println(" deftarget " + defTarget + " --> "+defTarget_x); + + trans = (HashMap) delta.get( state ); + HashMap newTrans = new HashMap(); + for( Iterator labs = labels.iterator(); labs.hasNext() ;) { + Object label = labs.next(); + TreeSet target = (TreeSet) trans.get( label ); + Integer target_x; + if( target != null ) { + // //System.out.println("target :"+target); + target_x = (Integer) indexMap.get( target ); + + if( target_x.intValue() != defTarget_x.intValue() ) { + // replace target by target_x + // (use type-unawareness) + newTrans.put( label, target_x ); + } + trans.remove( label ); + } + + } + ((HashMap[])deltaq)[ state_x.intValue() ] = newTrans; + ((Integer[])defaultq)[ state_x.intValue() ] = defTarget_x; + + delta.remove( state ); + deftrans.remove( state ); + + } + + TreeMap oldfin = finals; + this.finals = new TreeMap(); + for( Iterator it = oldfin.keySet().iterator(); it.hasNext(); ) { + TreeSet state = (TreeSet) it.next(); + Integer state_x = (Integer) indexMap.get( state ); + this.finals.put( state_x, oldfin.get( state ) );// conserve tags + } + + // clean up, delete temporary stuff + /* + // we cannot clean up, indexmap is needed later + for( Iterator it = states.iterator(); it.hasNext(); ) { + ((TreeSet) it.next()).clear(); + } + */ + states.clear(); + + //minimize(); + } + + public DetWordAutom() {} + + public boolean isDead( int state ) { + return state == nstates - 1; // by construction + } + + public boolean isDead( Integer state ) { + return state.intValue() == nstates - 1; // by construction + } + + /** determinization -- standard algorithm considering only + * reachable states + */ + public DetWordAutom( NondetWordAutom nfa ) { + determinize( nfa ); + } + + /** for a set of nfa states (that must exist), returns its transitions + */ + HashMap deltaq( TreeSet nset ) { + return (HashMap) deltaq( (Integer) indexMap.get( nset ) ); + } + + + /** for a set of nfa states (that must exist), returns its transitions + */ + Integer defaultq( TreeSet nset ) { + return (Integer) defaultq( (Integer) indexMap.get( nset ) ); + } + + /** returns target of the transition from state i with label label. + * null if no such transition exists. + */ + Integer delta( int i, Label label ) { + Integer target; + switch( label ) { + case DefaultLabel: + if( !hasDefault( i ) ) + return null; + return (Integer) defaultq( i ) ; + case SimpleLabel( _ ): + case TreeLabel( _ ): + return (Integer) ((HashMap[])deltaq)[ i ].get( label ) ; + /*case Pair( Integer state, Label lab ): + return state; + */ + default: + throw new ApplicationError("whut's this: label="+label+", class "+label.getClass()); + } + } + + Integer delta( Integer i, Label label ) { + return delta( i.intValue(), label ); + } + + /** should maybe in nfa, not here + */ + protected static Integer smallestFinal( NondetWordAutom nfa, + TreeSet states ) { + + int min = Integer.MAX_VALUE ; + for( Iterator it = states.iterator(); it.hasNext(); ) { + Integer state = (Integer) it.next(); + if( nfa.isFinal( state ) && (state.intValue() < min )) + min = state.intValue(); + } + if( min == Integer.MAX_VALUE ) + throw new ApplicationError("I expected a final set of states"); + return new Integer( min ); + + } + + protected Vector allSetsThatContain( Integer ndstate ) { + Vector v = new Vector(); + for( Iterator it = indexMap.keySet().iterator(); it.hasNext(); ) { + TreeSet ndstateSet = (TreeSet) it.next(); + if( ndstateSet.contains( ndstate )) + v.add( ndstateSet ); + } + return v; + } + + + protected void filterItOutQuoi( DetWordAutom dLeft, + Cartesian.Npair npTarget, + Label.Pair lab, + TreeMap nsrc ) { + Label theLabel = lab.lab; + Integer ntarget = lab.state; + + // e.g.[2,(3),4] --> 7 + Integer dstate = (Integer) dLeft.indexMap.get( npTarget.nset ); + + // eg. 3 -> [3] [2,3] + Vector targets = dLeft.allSetsThatContain( ntarget ); + + ////System.out.println( targets+", of these " ) ; + + // filter out those source states which arrive here... + + for( Iterator su = targets.iterator(); su.hasNext(); ) { + TreeSet nset = (TreeSet) su.next(); + + HashMap ddelta = (HashMap) dLeft.deltaq( nset ); + + // ... at THIS dstate + if( (Integer) ddelta.get( theLabel ) == dstate ) { + + Cartesian.Npair np1 = new Cartesian.Npair( ntarget, nset ); + + ////System.out.print( np1.toString( dLeft.indexMap )); + + if( WHICH_LONGEST_MATCH == FIRST ) + addTransitionFLM( nsrc, np1 ); + else + addTransitionLLM( nsrc, np1 ); + } + + } + } + + /** all default transitions from sets that contain nq to npTarget + */ + protected void filterItOutQuoiDefault( DetWordAutom dLeft, + Cartesian.Npair npTarget, + Integer nq, + TreeMap nsrc ) { + + + ////System.out.println( "npTarget = " + npTarget ) ; + + Vector allSources = dLeft.allSetsThatContain( npTarget.nstate ); + + for( Iterator it = allSources.iterator(); it.hasNext(); ) { + + // e.g.[2,(3),4] --> 7 + //Integer dstate = (Integer) dLeft.indexMap.get( npTarget.nset ); + + Integer dstate = (Integer) dLeft.indexMap.get( it.next() ); + + //System.out.println( "dstate = " + dstate ) ; + + assert dstate != null; + + // eg. 3 -> [3] [2,3] + Vector targets = dLeft.allSetsThatContain( nq ); + + //System.out.println( "targets: " + targets ) ; + + // filter out those source states which arrive here... + + for( Iterator su = targets.iterator(); su.hasNext(); ) { + TreeSet nset = (TreeSet) su.next(); + + Integer ddef = (Integer) dLeft.defaultq( nset ); + + //System.out.println( "ddef ="+ddef ); + + // ... at THIS dstate + if( ddef == dstate ) { + + Cartesian.Npair np1 = new Cartesian.Npair( nq, nset ); + + // print target + //System.out.print( np1.toString( dLeft.indexMap )); + + if( WHICH_LONGEST_MATCH == FIRST ) + addTransitionFLM( nsrc, np1 ); + else + addTransitionLLM( nsrc, np1 ); + + } + + } + } + } + + /** this implements the first longest match policy + */ + protected static void addTransitionFLM( TreeMap nsrc, Cartesian.Npair np ) { + Cartesian.Npair np2 = (Cartesian.Npair) nsrc.get( np.nset ); + + // (policy) first longest match + if(( np2 == null ) + ||( np2.nstate.intValue() > np.nstate.intValue())) { + nsrc.put( np.nset, np ); + } + + } + + /** this implements the last longest match policy (!) + */ + protected static void addTransitionLLM( TreeMap nsrc, Cartesian.Npair np ) { + Cartesian.Npair np2 = (Cartesian.Npair) nsrc.get( np.nset ); + + // (policy) first longest match + if(( np2 == null ) + ||( np2.nstate.intValue() < np.nstate.intValue())) { + nsrc.put( np.nset, np ); + } + + } + + + /** build a deterministic right to left transducer from the args + */ + public DetWordAutom( NondetWordAutom right, + NondetWordAutom left, + DetWordAutom dLeft ) { + + /* System.out.println("DetWordAutom.<init>(nfa,nfa,dfa)"); + System.out.println("nfa-left:");left.print(); + System.out.println("nfa-right:");right.print(); + System.out.println("dLeft:"+dLeft.print()); + System.out.println("dLeft.finals"+dLeft.finals); + */ + this.indexMap = dLeft.indexMap; + this.invIndexMap = dLeft.invIndexMap; + // fix indexMap + /* // unnecessary + TreeSet q0 = new TreeSet(); + q0.add( new Integer( 0 )); + indexMap.put( q0, new Integer( 0 )); + //System.out.println("check out the indexMap!" + indexMap); + */ + + TreeSet visited_n = new TreeSet( new NpairComparator() ); + Stack rest = new Stack(); + + // right is "nearly deterministic" + // we can follow reverse traces paths by using dLeft.indexMap + + // start with right.initials, left.final, dLeft.final + for( Iterator it = dLeft.finals.keySet().iterator(); it.hasNext(); ) { + Integer fstate = (Integer) it.next(); + TreeSet nfstate = (TreeSet) invIndexMap.get( fstate ); + //System.out.print( "final state:"+fstate); + //System.out.print( " correspond to set of states:"+ nfstate ); + + Integer min_ndstate = smallestFinal( left, nfstate ); + + Cartesian.Npair npair = new Cartesian.Npair( min_ndstate, nfstate ); + + //System.out.println( " smallest final of these: "+ min_ndstate ); + + + //System.out.println( "push final nfa state "+npair.toString( dLeft.indexMap )); + + if( !visited_n.contains( npair )) { + visited_n.add( npair ); + rest.push( npair ); + } + } + + HashMap ratLab = new HashMap(); // maps nset to label,HashMap + HashMap ratDelta = new HashMap(); // maps nset to Vector[ NP ]targets + + HashMap ratDefault = new HashMap(); // maps nset to NP (one target) + + int ix = 1; + Stack ix_initial = (Stack) rest.clone(); + TreeSet ix_final = new TreeSet( new NpairComparator() );; + + TreeMap newIndexMap = new TreeMap( new NpairComparator() ); + + while( !rest.isEmpty() ) { + + Cartesian.Npair npair = (Cartesian.Npair) rest.pop(); + newIndexMap.put( npair, new Integer(ix)); + + ratDelta.put( npair, new Vector() ); + + if( npair.nset.contains( new Integer( 0 )) ) { + ix_final.add( npair ); + } + ix++; + + //System.out.println(" popped "+npair.toString( dLeft.indexMap )); + + ////System.out.print(" binders: "); + ////System.out.print( right.qbinders[ npair.nstate.intValue() ] ); + + HashMap delta = (HashMap) right.deltaq( npair.nstate ); + + ////System.out.print(" we could have arrived : "); + //search the delta for target invIndexMap + + HashMap labelToNset = new HashMap(); + HashMap labelToFrom = new HashMap(); + + // maps nsets to the active nstates + TreeMap nsrc = new TreeMap( new StateSetComparator() ); + + // berry-sethi construction assures that + // there is only one label for outgoing transitions + Label theLabel = null; + + // collect all transition possible in the DFA + + for( Iterator it = delta.keySet().iterator(); it.hasNext(); ) { + + Label.Pair lab = (Label.Pair) it.next(); + + // lab.state is the target in the NFA + + if( theLabel == null ) { + ratLab.put( npair, lab.lab ); + ////System.out.print(" with \""+lab.lab+"\" "); + } + theLabel = lab.lab ; + + ////System.out.print("\nfrom n" + lab.state +" ... "); + + // these are too many, filter out those that exist in DFA + + filterItOutQuoi( dLeft, npair, lab, nsrc ); + + } + + + ////System.out.println( "---" ); + + ////System.out.println("all sources: "); + + // !! first longest match + + for( Iterator ut = nsrc.keySet().iterator(); ut.hasNext(); ) { + TreeSet nset = (TreeSet) ut.next(); + + Cartesian.Npair np2 = (Cartesian.Npair) nsrc.get( nset ); + + assert( np2 != null ); + ////System.out.println("target: n"+npair.nstate+" via: "+theLabel+" from "+ np2.toString( dLeft.indexMap ));// nset:"+nset+ " namely state n"+ dest); + + Vector v = (Vector) ratDelta.get( npair ); + + v.add( np2 ); + + if( !visited_n.contains( np2 ) ) { + + visited_n.add( np2 ); + rest.push( np2 ); + } + + } + + //System.out.println("default sources: "); + + // maps nsets to the active nstates + nsrc = new TreeMap( new StateSetComparator() ); + + // now for all default transitions that arrive at this nfa state + Vector defqs = (Vector) right.defaultq( npair.nstate ); + for( Iterator it = defqs.iterator(); it.hasNext(); ) { + Integer nq = (Integer) it.next(); + //System.out.println("checking nq="+nq); + filterItOutQuoiDefault( dLeft, npair, nq, nsrc ); + //System.out.println( "nsrc after "+nq+" is "+nsrc ); + } + + //System.out.println( "defqs :"+defqs ); + //System.out.println( "nsrc :"+nsrc ); + + for( Iterator ut = nsrc.keySet().iterator(); ut.hasNext(); ) { + + Cartesian.Npair np2 = (Cartesian.Npair) nsrc.get( ut.next() ); + + Vector v = (Vector) ratDefault.get( npair ); + if( v == null ) + ratDefault.put( npair, v = new Vector() ); + v.add( np2 ); + + if( !visited_n.contains( np2 ) ) { + + visited_n.add( np2 ); + rest.push( np2 ); + } + + } + + ////System.out.println("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"); + + } + + // Renumbering + + ////System.out.println( "output: a dfa with "+ix+"states"); + assert ( !ix_final.isEmpty() ) : "no final states found"; + ////System.out.println( "final state:"+ix_final); + + //System.out.println( "indexMap: " +indexMap); + //System.out.println( "newIndexMap: " +newIndexMap); + this.finals = new TreeMap(); + this.nstates = ix; + HashMap dratDelta[] = new HashMap[ ix ]; + qbinders = new Vector[ ix ]; + labels = new HashSet(); + for( Iterator it = ratDelta.keySet().iterator(); it.hasNext(); ) { + Cartesian.Npair np = (Cartesian.Npair) it.next(); + + //System.out.print( "\nstate: "+np); + TreeSet ndset = np.nset; + Integer dstate = (Integer) newIndexMap.get( np ); + assert dstate != null : "no dstate for "+np.toString(dLeft.indexMap); + + //System.out.print(" binders:"); + + qbinders[ dstate.intValue() ] = left.qbinders[ np.nstate.intValue() ]; + + //System.out.print( qbinders[dstate.intValue() ]); + + //System.out.println(" transitions:"); + if( ix_final.contains( np ) ) { + Integer fin_ix = (Integer) newIndexMap.get( np ); + finals.put( fin_ix, new Integer( 0 )); + } + + Label lab = (Label) ratLab.get( np ); + Vector v = (Vector) ratDelta.get( np ); + + HashMap ddelta = new HashMap(); + + // v might be null if there are only default transitions + if( v != null ) + for( Iterator it2 = v.iterator(); it2.hasNext() ; ) { + + Cartesian.Npair np2= (Cartesian.Npair) it2.next(); + //System.out.print( "("+lab+","+np2+") " ); + Integer ddestR = (Integer) newIndexMap.get( np2 ); + Integer ddest = (Integer) indexMap.get( np2.nset ); + assert ddest != null : + "no ddest for " + +np2.toString(dLeft.indexMap); + + Label.Pair newLab = new Label.Pair(ddest, lab); + ddelta.put( newLab, ddestR ); + labels.add( newLab ); + + } + dratDelta[ dstate.intValue() ] = ddelta; + + } + + for( Iterator it = ratDefault.keySet().iterator(); it.hasNext(); ) { + Cartesian.Npair np = (Cartesian.Npair) it.next(); + Integer dstate = (Integer) newIndexMap.get( np ); + + //System.out.print("\nstate: "+np+" default trans: "); + + Vector v = (Vector) ratDefault.get( np ); + for( Iterator ut = v.iterator(); ut.hasNext(); ) { + Cartesian.Npair np2 = (Cartesian.Npair) ut.next(); + Integer targetL = (Integer) indexMap.get( np2.nset ); + Integer targetR = (Integer) newIndexMap.get( np2 ); + + Label defLab = new Label.Pair( targetL, + Label.DefaultLabel ); + + labels.add( defLab ); + //System.out.print( "("+defLab+","+np2+") " ); + + HashMap d = dratDelta[ dstate.intValue() ]; + if( d == null ) + dratDelta[ dstate.intValue() ] = d = new HashMap(); + + d.put( defLab, targetR ); + } + } + + deltaq = dratDelta; + + HashMap hmap = new HashMap(); + + // final states of left are initial states of right + // problem: still need to choose the one + + while( !ix_initial.isEmpty() ) { + Cartesian.Npair np = (Cartesian.Npair) ix_initial.pop(); + + Integer i = (Integer) newIndexMap.get( np ); //R-state + Integer dtarget = (Integer) indexMap.get( np.nset );// left-d-state + + hmap.put( dtarget, i ); + } + ((HashMap[])deltaq)[ 0 ] = hmap; // careful, this maps Int to Int + + qbinders[ 0 ] = new Vector(); + //((Vector[])defaultq)[ 0 ] = new Vector(); is null + printBeforeRAT( dratDelta ); + + } + + void printBeforeRAT1( String str ) { + StringBuffer tmp = new StringBuffer( str ); + for( int j = tmp.length(); j < 20; j++ ) { + tmp.append(" "); + } + //System.out.print( tmp.toString() ); + } + + void printBeforeRAT( HashMap dratDelta[] ) { + //System.out.println(); + printBeforeRAT1( "dratDelta" ); + printBeforeRAT1( "[index]" ); + //System.out.println(); + + for( int i = 0; i < dratDelta.length; i++ ) { + if( isFinal( i )) + printBeforeRAT1( "*"+i ); + else + printBeforeRAT1( " "+i ); + + //System.out.println( dratDelta[ i ] ); + } + } + + /** you may only call this before the set[set[...]] representation + * gets flattened. + */ + public void printBefore( TreeSet states, HashMap deftrans ) { + HashMap trans; + //System.out.println( states ); + for( Iterator it = states.iterator(); it.hasNext(); ) { + TreeSet state = (TreeSet) it.next(); + //System.out.print("state:"+state.toString()+" transitions "); + trans = (HashMap) delta.get( state ); + for( Iterator labs = labels.iterator(); labs.hasNext() ;) { + Object label = labs.next(); + TreeSet target = (TreeSet) trans.get( label ); + //System.out.print( " (" + label.toString() + // + "," + target.toString()+")"); + } + //System.out.print("default trans"+deftrans.get( state )); + //System.out.println(); + } + //System.out.println("final states:" + finals ); + } + + + /* + public void minimize() { // TO DO + //System.out.println("minimization"); + boolean mark[][] = new boolean[nstates][]; + for( int i = 0; i < nstates; i++ ) { + mark[i] = new boolean[nstates - i]; + for( int j = 0; j < (nstates - i); j++ ) + mark[i][j] = false; + } + debugPrint( mark ); + } + + protected void debugPrint( boolean mark[][] ) { + for( int i = 0; i < nstates; i++ ) { + //System.out.print("["); + for( int j = 0; j < nstates - i; j++ ) { + //System.out.print(" "+mark[i][j]); + if( mark[i][j] ) + //System.out.print(" "); + } + //System.out.println(" ]"); + } + } + + */ + + /* + + public void createDeadState() { + assert dead == -1; + this.dead = this.nstates++; + Integer deadI = new Integer( dead ); + + HashMap odelta[] = ((HashMap[])deltaq); + deltaq = new HashMap[ this.nstates ]; + System.arraycopy(odelta, 0, ((HashMap[])deltaq), 0, odelta.length); + HashMap trans = new HashMap(); + ((HashMap[])deltaq)[ this.dead ] = trans; + for( Iterator labs = labels.iterator(); labs.hasNext(); ) { + trans.put( labels, deadI ); + } + //System.out.println("createDeadState, new dead state:"+dead); + } + + + + // adjusts the alphabet of this automaton + + public void addLabels( HashSet labels ) { + + for(Iterator it = labels.iterator(); it.hasNext(); ) { + Object label = it.next(); + if( this.labels.add( label )) { // new + // adjust all transitions + + if( this.dead == -1 ) + createDeadState(); + + Integer deadI = new Integer( this.dead ); + + for( int i = 0; i < this.nstates; i++ ) { + ((HashMap[])deltaq)[ i ].put( label, deadI ); + } + } + } + } + */ + + // wishlist for jaco: why does Cartesian have to be static ? + // if not, error "inner classes must not have static members" + + /** cartesian + */ + + static class Cartesian { + /** Int x TreeSet[ Int ] + */ + case Npair(Integer nstate, TreeSet nset); + + public boolean equals( Object that ) { + if( !(that instanceof Cartesian )) + return false; + switch( this ) { + case Npair( Integer nstate, TreeSet nset ): + switch((Cartesian) that) { + case Npair( Integer _nstate, TreeSet _nset ): + return ((nstate == _nstate) + &&( nset == _nset )); + } + } + return false; + } + + public String toString() { + switch( this ) { + case Npair( Integer nstate, TreeSet nset ): + //Integer dstate = (Integer) indexMap.get( nset ); + return "<n"+nstate.toString()+" in "+nset /*+" = d"+dstate*/+">"; + } + return null; + } + + public String toString( HashMap indexMap ) { + //assert indexMap != null; + switch( this ) { + case Npair( Integer nstate, TreeSet nset ): + assert nstate!=null; + Integer dstate = (Integer) indexMap.get( nset ); + return "<n"+nstate.toString()+" in "+nset +" = d"+dstate +">"; + } + return null; + } + + + } + + static class NpairComparator extends StateSetComparator { + public int compare( Object o1, Object o2 ) { + if(( o1 instanceof Cartesian.Npair )&& + ( o2 instanceof Cartesian.Npair )) + switch((Cartesian) o1) { + case Npair( Integer nstate, TreeSet nset ): + switch( (Cartesian) o2 ) { + case Npair( Integer _nstate, TreeSet _nset ): + int res = nstate.compareTo( _nstate ); + + ////System.out.println("nstate"+nstate+" <> _nstate "+ _nstate+" res"+res); + if( res != 0 ) + return res; + else + return super.compare( nset, _nset ); + } + } + throw new ApplicationError( "illegal arg. to compare. " + +o1.getClass()+" "+o2.getClass()); + } + } + +} diff --git a/sources/scalac/transformer/matching/FiniteAutom.java b/sources/scalac/transformer/matching/FiniteAutom.java new file mode 100644 index 0000000000..f075e4aa93 --- /dev/null +++ b/sources/scalac/transformer/matching/FiniteAutom.java @@ -0,0 +1,120 @@ +package scalac.transformer.matching ; + +import java.util.Iterator ; +import java.util.HashSet ; +import java.util.HashMap ; +import java.util.TreeSet ; +import java.util.TreeMap ; + +public abstract class FiniteAutom { + + //final static Integer FINTAG = new Integer(0); + + /** number of states */ + protected int nstates; + + /** the 'alphabet' */ + protected HashSet labels; + + /** the set of final states, here as a TreeMap */ + protected TreeMap finals; + + /** dfa: HashMap trans: Object -> Integer + * nfa: HashMap trans: Object -> Vector [ Integer ] + * + * nfa: Integer ->(Object -> Vector [ Int ]) + * [q] |->( a |-> { q' | (q,a,q') in \deltaright } ) + * + * dfa: Integer ->(Object -> Int) + * [q] |->( a |-> q' | \deltaright(q,a) = q' } ) + */ + + public Object deltaq; + + public Object defaultq; // this gives the default transitions + + //protected HashMap deltaq[]; + + // --- accessor methods + + /** returns number of states + */ + public int nstates() { + return nstates; + } + + /** returns the labels + */ + public HashSet labels() { + return labels; + } + + /** returns the transitions + */ + public Object deltaq( int state ) { + return ((Object []) deltaq)[ state ]; + } + + /** returns the transitions + */ + public Object deltaq( Integer state ) { + return ((Object []) deltaq)[ state.intValue() ]; + } + + + /** returns the transitions + */ + public Object defaultq( int state ) { + return ((Object []) defaultq)[ state ]; + } + + /** returns the transitions + */ + public Object defaultq( Integer state ) { + return ((Object []) defaultq)[ state.intValue() ]; + } + + + /** returns true if the state is final + */ + public boolean isFinal( int state ) { + return ((finals != null) + && (finals.get( new Integer( state )) != null)); + } + + /** returns true if the state is final + */ + public boolean isFinal( Integer state ) { + return ((finals != null) && finals.containsKey( state )); + } + + /** returns true if the state is final + */ + public Integer finalTag( Integer state ) { + return (Integer) finals.get( state ); + } + + + public Integer finalTag( int state ) { + return (Integer) finals.get( new Integer (state )); + } + + /** returns true if the set of states contains at least one final state + */ + boolean containsFinal( TreeSet Q ) { + for( Iterator it = Q.iterator(); it.hasNext(); ) { + if( isFinal( (Integer) it.next())) + return true; + } + return false; + } + + + /** returns true if there are no finite states + */ + public boolean isEmpty() { + return finals.isEmpty(); + } + + +} diff --git a/sources/scalac/transformer/matching/Label.java b/sources/scalac/transformer/matching/Label.java new file mode 100644 index 0000000000..389139da0a --- /dev/null +++ b/sources/scalac/transformer/matching/Label.java @@ -0,0 +1,120 @@ +package scalac.transformer.matching ; + +import scalac.ast.Tree ; +import scalac.symtab.Type ; +import Tree.Literal ; + +/** this class represents the label that a transition in an automaton may carry. + * these get translated to specific (boolean) tests + */ + +public class Label { + + + public case DefaultLabel; + public case SimpleLabel( Literal lit ); + public case TreeLabel( Tree pat ); // Apply, Sequence + + public case TypeLabel( Type tpe ); // Apply, Sequence + + public case Pair( Integer state, Label lab ); + + //public case RLabel( Object rstate, Label lab, Symbol vars[] ); + + public int hashCode() { + switch( this ) { + case DefaultLabel: + return 0; + case SimpleLabel( Literal lit ): + return lit.value.hashCode(); + case TreeLabel( Tree pat ): + return pat.hashCode(); + case TypeLabel( Type type ): + return type.hashCode(); + default: + return super.hashCode(); + } + } + + public boolean equals( Object o ) { + if( !(o instanceof Label )) + return false; + Label oL = (Label) o; + //System.out.print(this + " equals " + oL); + switch( this ) { + case DefaultLabel: + switch( oL ) { + case DefaultLabel: + return true; + } // + break; + case SimpleLabel( Literal lit ): + switch( oL ) { + case SimpleLabel( Literal lit2 ): + return /*(lit.kind == lit2.kind) + && */lit.value.equals( lit2.value ); + } + break; + case TreeLabel( Tree pat ): + switch( oL ) { + case TreeLabel( Tree pat2): + return pat == pat2; + } + break ; + case TypeLabel( Type tpe ): + switch( oL ) { + case TypeLabel( Type tpe2): + return tpe.equals( tpe2 ); + } + break ; + case Pair( Integer state, Label lab ): + switch( oL ) { + case Pair( Integer state2, Label lab2 ): + return state.equals( state2 ) + && lab.equals( lab2 ) ; + } + break; + } + return false; + } + + + public String toString2() { + String ext = System.getProperty("extendedMatching"); + if(( ext != null ) + && ext.equals( "true" )) { + switch( this ) { + case DefaultLabel: + return "<>:p"+p; + case SimpleLabel( Literal lit ): + return lit.toString()+":p"+p; + case TreeLabel( Tree pat ): + return pat.type()+":p"+p; + + } + } + throw new scalac.ApplicationError + ("this never happens"); + } + + public String toString() { + + switch( this ) { + case DefaultLabel: + return "<>"; + case SimpleLabel( Literal lit): + return lit.toString(); + case TreeLabel( Tree pat): + return pat.toString(); + case TypeLabel( Type tpe ): + return tpe.toString(); + case Pair( Integer state, Label lab ): + return "("+state.toString()+","+lab.toString()+")"; + } + throw new scalac.ApplicationError("this never happens"); + } + + int p = -1; // tree state - only needed for extended matching + + +} diff --git a/sources/scalac/transformer/matching/NondetWordAutom.java b/sources/scalac/transformer/matching/NondetWordAutom.java new file mode 100644 index 0000000000..f4a7458f52 --- /dev/null +++ b/sources/scalac/transformer/matching/NondetWordAutom.java @@ -0,0 +1,409 @@ +package scalac.transformer.matching ; + +import scalac.ApplicationError ; +import scalac.ast.Tree ; +import scalac.util.Name ; +import Tree.* ; + +import java.util.* ; + +//import scala.compiler.printer.TextTreePrinter ; + +/** a nondeterministic word automaton. + * states are represented (implicitly) as Integer objects. + */ + +public class NondetWordAutom extends FiniteAutom { + + // inherited from FiniteAutom + + // set of *distinct* objects that may label transitions + // see Object.hashCode() to see why this works + + //HashSet labels; + //TreeMap finals; + + TreeSet initials; // ? need this ? + // --- + + // Object deltaq --> + // HashMap deltaq[]; // this gives the transitions of q; + + boolean leftTrans; + boolean rightTrans; + + /** if true, this automaton behaves as a special left transducer. + * if a run succeeds, the result is not "true" but the entire + * run of the automaton as a sequence of (label,state) - pairs. + * used for binding variables. + */ + public boolean producesRun() { + return leftTrans; + } + + public boolean consumesRun() { + return rightTrans; + } + + public boolean initial( Integer i ) { + return initials.contains( i ); + } + public Vector qbinders[]; + + /** returns all states accessible from Qsrc via label. + * used by class DetWordAutomaton. + */ + TreeSet getSide ( TreeSet Qsrc, Object label ) { + TreeSet Qdest = new TreeSet(); + for( Iterator it = Qsrc.iterator(); it.hasNext(); ) { + // state + int q1 = ((Integer) it.next()).intValue(); + Vector ps = (Vector) ((HashMap[])deltaq)[ q1 ].get( label ); + + //System.out.println( "q1 "+q1+" targ:"+ps.toString() ); + if( ps!=null ) + Qdest.addAll( ps ); + + Qdest.addAll((Vector) defaultq( q1 )); + } + return Qdest; + } + + /** returns the transitions + */ + public Object defaultq( Set P1 ) { + TreeSet defTarget = new TreeSet(); + for( Iterator p1 = P1.iterator(); p1.hasNext(); ) { + int q1 = ((Integer) p1.next()).intValue(); + //System.out.println(" q1:"+q1+ " defa: "+defaultq( q1 )); + defTarget.addAll( (Vector) defaultq( q1 )); + } + return defTarget; + } + + + /** first match policy: among several final states, the smallest one is + * chosen. used by class DetWordAutomaton + */ + Integer finalTag( Set Q ) { + + int min = Integer.MAX_VALUE ; + + for( Iterator it = Q.iterator(); it.hasNext(); ) { + Integer state = (Integer) it.next(); + Integer tag = (Integer) finals.get( state ); + if( tag != null ) { + if( tag.intValue() < min ) + min = tag.intValue(); + } + } + + if ( min == Integer.MAX_VALUE ) + throw new ApplicationError( "there should be a final state "); + + return new Integer( min ); + } + + /* + protected void tmap(int offs, TreeMap t) { + TreeMap nt = new TreeMap(); + for(Iterator it = t.keySet().iterator(); it.hasNext(); ) { + Integer key = (Integer) it.next(); + Integer newkey = new Integer( key.intValue() + offs ); + Integer val = (Integer) t.get( key ); + Integer newval = new Integer( val.intValue() + offs ); + + nt.put( newkey, newval ); + } + return nt; + } +*/ + // hashmaps, treemaps + protected Map mapmap(Map src, + int offset, + Map dest, + boolean mapkeys, + boolean mapvals) { + for(Iterator it = src.keySet().iterator(); it.hasNext(); ) { + Object key = it.next(); + Object val = src.get( key ); + if( mapkeys ) key = new Integer( ((Integer)key).intValue() + + offset ); + if( mapvals ) val = vmap( offset, (Vector) val ) ; + /* new Integer( ((Integer)val).intValue() + + offset ); + */ + dest.put( key, val ); + } + return dest; + } + + protected static Vector vmap(int offs, Vector v ) { + if( v == null ) + return null; + Vector res = new Vector( v.size() ); + + for(Iterator it = v.iterator(); it.hasNext(); ) { + Integer item = (Integer) it.next(); + res.add( new Integer( item.intValue() + offs )); + } + return res; + + } + + /* + protected void relocate_defaultq( int offs, Vector _defaultq[] ) { + for( int i = 0; i < this.nstates; i++ ) { + _defaultq[ i + offset ] = vmap( offset, ((Vector[])defaultq)[ i ]); + } + } + */ + + /** copies the values in the fields of this object into the + * arguments, possibly adding an offset. + */ + protected void relocate( int offset, + TreeMap _finals, + HashMap _deltaq[], + Vector _defaultq[], + Vector _qbinders[] ) { + + mapmap( finals, offset, _finals, true, false); + + for( int i = 0; i < this.nstates; i++ ) { + + _deltaq [ i + offset ] = (HashMap) mapmap( ((HashMap[])deltaq)[ i ], + offset, new HashMap(), false, true); + + _defaultq[ i + offset ] = vmap( offset, ((Vector[])defaultq)[ i ]); + + } + if ((_qbinders != null) &&( qbinders != null )) + for( int i = 0; i < this.nstates; i++ ) { + //System.out.println("hallo"+qbinders); + //System.out.println("qbinders[ i ] :"+qbinders[ i ]); + assert _qbinders != null; + //System.out.println("_qbinders :"+_qbinders); + + _qbinders[ i + offset ] = qbinders[ i ]; + } + } + + /** if there is more than one initial state, a new initial state + * is created, with index 0 + */ + protected void normalize( TreeSet initials, boolean reloc ) { + //if( initials.size() == 1 ) + // return; + + HashMap idelta = new HashMap(); + TreeSet idefault = new TreeSet(); + + Integer q0 = new Integer( 0 ); + + for( Iterator it = initials.iterator(); it.hasNext(); ) { + + Integer ostate = (Integer) it.next(); + + Integer finTag = (Integer) finals.get( ostate ) ; + if(( finTag != null ) && ( finals.get( q0 ) == null)) + finals.put( q0, finTag ); + + + HashMap tmp = (HashMap) deltaq( ostate ); + + if( reloc ) + tmp = (HashMap) mapmap( tmp, 1, new HashMap(), false, true ); + + for( Iterator labs = tmp.keySet().iterator(); labs.hasNext(); ) { + Label lab = (Label) labs.next(); + Vector itarget = (Vector) idelta.get( lab ); + if( itarget == null ) + idelta.put( lab, itarget = new Vector()); + Vector otarget = (Vector) tmp.get( lab ); + itarget.addAll( otarget ); + } + //System.out.println( "normalize:defaultq[ "+ostate+" ] "+((Vector[]) defaultq) [ ostate.intValue() ]); + if( defaultq( ostate ) != null ) + idefault.addAll( (Vector) defaultq( ostate ) ); + } + + if( reloc ) { + int m = 1 + this.nstates; + TreeMap _finals = new TreeMap(); + HashMap _deltaq[] = new HashMap[ m ]; + Vector _defaultq[] = new Vector[ m ]; + Vector _qbinders[] = null; + + if( qbinders != null ) + _qbinders = new Vector[ m ]; + + relocate( 1, _finals, _deltaq, _defaultq, _qbinders ); + + this.nstates = m; + this.finals = _finals; + this.deltaq = _deltaq; + this.defaultq = _defaultq; + this.qbinders = _qbinders; + } + + ((HashMap[])this.deltaq) [ 0 ] = idelta; + //System.out.println("normalize:deltaq[ 0 ]"+ idelta ); + ((Vector[])this.defaultq) [ 0 ] = new Vector( idefault ); + + //System.out.println("normalize:defaultq[ 0 ]"+ idefault ); + + this.initials = new TreeSet(); + this.initials.add( q0 ); + } + + + /** needed for NondetWordSwitch + */ + NondetWordAutom() {} + + /** called from Berry-Sethi construction. + */ + + public NondetWordAutom(int nstates, + HashSet labels, + TreeSet initials, + TreeMap finals, + Object deltaq, + Object defaultq, + Object qbinders) { + this.nstates = nstates; + this.labels = labels; + this.initials = initials; + this.finals = finals; + this.deltaq = deltaq; + this.defaultq = defaultq; + this.qbinders = (Vector[])qbinders; + //print(); + //System.exit(0); + } + + + + int offset[]; // only used if constructed from multiple + + protected void collectLabels( NondetWordAutom nfa[] ) { + this.labels = new HashSet(); + for( int i = 0; i < nfa.length; i++ ) { + this.labels.addAll( nfa[ i ].labels ); + } + } + + protected void collectOffsets( NondetWordAutom nfa[] ) { + this.offset = new int[ nfa.length + 1 ]; + offset[ 0 ] = 1; // we have a new initial state + for( int i = 0; i < nfa.length ; i++ ) + offset[ i + 1 ] = nfa[ i ].nstates + offset[ i ]; + + } + + /** collapses several normalized NondetWordAutom objects into one. + */ + + public NondetWordAutom( NondetWordAutom nfa[] ) { + + + //this.m + int m = nfa.length; + //System.out.println("enter NondetWordSwitch, " + // +"combining " + m + " automata"); + + collectLabels( nfa ); + collectOffsets( nfa ); + + this.nstates = offset[ nfa.length ]; //m - 1 ] + nfa[ m - 1 ].nstates; + + + this.finals = new TreeMap(); + + this.qbinders = new Vector[ nstates ]; + + // new initial state gets all transitions from all initial states + + this.deltaq = new HashMap[ nstates ]; + this.defaultq = new Vector [ nstates ]; + + //TreeSet defaultqSet = new TreeSet(); + ((HashMap [])deltaq)[ 0 ] = new HashMap(); // 0 = our new initial state + + TreeSet initials = new TreeSet(); + + + for( int i = 0; i < m; i++ ) { + //System.out.println("i (current NFA):"+i); + + NondetWordAutom n = nfa[ i ]; + + int offs = offset[ i ]; + + initials.add( new Integer( offs )); + + n.relocate( offs, + this.finals, + (HashMap[]) this.deltaq, + (Vector[]) this.defaultq, + (Vector[]) this.qbinders ); + } + + normalize( initials, false ); + + } + + + + + public void print() { + + System.out.print("NFA on labels "+ this.labels); + + if( offset != null ) { + System.out.print("offset"); + for( int k = 0; k < offset.length; k++ ) { + if( k > 0) + System.out.print(", "); + System.out.print(offset[k]); + } + } + System.out.println(); + + System.out.print("max state number :" + (nstates - 1) ); + + System.out.println("initials" + initials); + + System.out.println("finals" + finals); + + for( int i = 0; i < nstates; i++ ) { + System.out.print("state: " + i); + if( finals.containsKey( new Integer( i )) ){ + System.out.print("*"); //final + } + System.out.print(" transitions: {"); + HashMap arrows = ((HashMap[])deltaq)[ i ]; + + for( Iterator it = arrows.keySet().iterator(); + it.hasNext(); ) { + Object label = it.next(); + Vector targets = (Vector) arrows.get( label ); + for( Iterator jt = targets.iterator(); + jt.hasNext(); ) { + Integer p = (Integer) jt.next(); + System.out.print("("+label+","+p+")"); + } + } + + System.out.print("} "); + System.out.print(" default transitions: "+defaultq( i )); + if( qbinders != null ) + System.out.println(" binders "+qbinders[ i ]); + System.out.println(); + + } + + } + +} diff --git a/sources/scalac/transformer/matching/StateSetComparator.java b/sources/scalac/transformer/matching/StateSetComparator.java new file mode 100644 index 0000000000..71c43b2374 --- /dev/null +++ b/sources/scalac/transformer/matching/StateSetComparator.java @@ -0,0 +1,34 @@ +package scalac.transformer.matching ; + +import java.util.* ; + +class StateSetComparator implements Comparator { + // use lexicographic order + public int compare( Object o1, Object o2 ) { + /* + System.out.print("lexi" ); + System.out.print( o1 +" "); + System.out.println( o2 ); + */ + Iterator it1 = ((TreeSet) o1).iterator(); + Iterator it2 = ((TreeSet) o2).iterator(); + while( it1.hasNext() ) { + while( it2.hasNext() ) { + if( !it1.hasNext() ) + return -1; + + int i1 = ((Integer) it1.next()).intValue(); + int i2 = ((Integer) it2.next()).intValue(); + if( i1 < i2 ) + return -1; + else if ( i1 > i2 ) + return 1; + } + if( it1.hasNext() ) + return 1; + } + if( it2.hasNext() ) + return -1; + return 0; + } + } |