it all works
authoradam <adam@megacz.com>
Thu, 5 Jan 2006 07:39:30 +0000 (02:39 -0500)
committeradam <adam@megacz.com>
Thu, 5 Jan 2006 07:39:30 +0000 (02:39 -0500)
darcs-hash:20060105073930-5007d-0aa9bef7e97fbe87265879b06083b3ebca3522de.gz

TODO
src/edu/berkeley/sbp/Forest.java
src/edu/berkeley/sbp/GSS.java
src/edu/berkeley/sbp/Parser.java
src/edu/berkeley/sbp/Sequence.java
src/edu/berkeley/sbp/util/FastSet.java
src/edu/berkeley/sbp/util/TopologicalBag.java
tests/input.tibdoc
tests/regression.tc
tests/tibdoc.g

diff --git a/TODO b/TODO
index 3e67a2e..31d33a0 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,14 +3,11 @@ Immediately
 
   - Performance
 
-     - Next target: TopologicalBag (make it wickedfast: preoptimize)
-
      - Forest: keep() and valid() -- can we do this with states
        rather than subtrees?
 
      - hash Long->long: it's all bogus
 
-  * huge performance improvement (try for more)
   * pick back up cleaning up end of Parser.java (Reduction)
   * some weird edge cases; check last regression test, 'make doc'
 
index 6437341..5c09170 100644 (file)
@@ -44,6 +44,7 @@ public abstract class Forest<T> {
             this.tag = tag;
             this.tokens = tokens==null ? emptyForestArray : new Forest[tokens.length];
             if (tokens != null) System.arraycopy(tokens, 0, this.tokens, 0, tokens.length);
+            if (tokens != null) for(int i=0; i<tokens.length; i++) if (tokens[i]==null) throw new Error(i+"");
             this.creator = creator;
             this.unwrap = unwrap;
             this.singleton = singleton;
@@ -103,20 +104,26 @@ public abstract class Forest<T> {
             return needs <= -1 * creator.needs.size();
         }
 
-
+        private boolean rep = false;
         public String toString() {
-            StringBuffer ret = new StringBuffer();
-            for(int i=0; i<tokens.length; i++) {
-                String q = tokens[i]==null ? "null" : tokens[i].toString();
-                if (q.length() > 0) {
-                    ret.append(q);
-                    ret.append(" ");
+            if (rep) return "***";
+            try {
+                rep = true;
+                StringBuffer ret = new StringBuffer();
+                for(int i=0; i<tokens.length; i++) {
+                    String q = tokens[i]==null ? "null" : tokens[i].toString();
+                    if (q.length() > 0) {
+                        ret.append(q);
+                        ret.append(" ");
+                    }
                 }
+                String tail = ret.toString().trim();
+                String head = (tag!=null && !tag.toString().equals("")) ? (tail.length() > 0 ? tag+":" : tag+"") : "";
+                if (tail.length() > 0) tail = "{" + tail + "}";
+                return head + tail;
+            } finally {
+                rep = false;
             }
-            String tail = ret.toString().trim();
-            String head = (tag!=null && !tag.toString().equals("")) ? (tail.length() > 0 ? tag+":" : tag+"") : "";
-            if (tail.length() > 0) tail = "{" + tail + "}";
-            return head + tail;
         }
     }
 
@@ -138,9 +145,10 @@ public abstract class Forest<T> {
         public boolean valid = false;
         public Ref() { }
         public void merge(Forest p) {
+            //if (p==null) throw new Error("bad evil bad!");
             if (res != null) throw new Error("already resolved!");
             if (p==null) throw new Error();
-            if (p!=this) hp.add(p);
+            if (p!=this) hp.add(p, true);
         }
         public Iterator<Body<T>> iterator() { return ((IterableForest<T>)resolve()).iterator(); }
         public HashSet<Tree<T>> expand(boolean toss) { return resolve().expand(toss); }
@@ -152,8 +160,12 @@ public abstract class Forest<T> {
             FastSet<Body> nh      = new FastSet<Body>();
             for(Forest<?> p : hp)
                 for(Body<?> b : (IterableForest<?>)p) {
-                    if (b.keep() && (b.creator==null || !b.creator.lame)) { valid = true; b.addTo(nh); }
-                    else results = new HashSet<Body>();
+                    if (b.keep() && (b.creator==null || !b.creator.lame)) {
+                        valid = true;
+                        b.addTo(nh);
+                    } else {
+                        results = new HashSet<Body>();
+                    }
                 }
             if (results != null) {
                 for(Forest<?> p : hp)
@@ -168,7 +180,8 @@ public abstract class Forest<T> {
                 }
             }
             hp = null;
-            return res = new MultiForest(nh, valid);
+            res = new MultiForest(nh, valid);
+            return res;
         }
     }
 
index 1d401a5..16725f1 100644 (file)
@@ -73,23 +73,22 @@ class GSS {
          *  @param fromEmptyReduction true iff this node is being created as a result of a reduction of length zero (see GRMLR paper)
          *  @param start              the earliest part of the input contributing to this node (used to make merging decisions)
          */
-        public void newNode(Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction, Phase start) {
-            Node p = hash.get(code(state, start));
-            if (p != null)  newNode2(p, parent, pending, state, fromEmptyReduction, start);
-            else            newNode3(parent, pending, state, fromEmptyReduction, start);
+        public void newNode(Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction) {
+            Node p = hash.get(code(state, parent==null?null:parent.phase()));
+            if (p != null)  newNode2(p, parent, pending, state, fromEmptyReduction);
+            else            newNode3(parent, pending, state, fromEmptyReduction);
         }
-        private void newNode2(Node p, Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction, Phase start) {
+        private void newNode2(Node p, Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction) {
             p.holder.merge(pending);
             if (p.parents().contains(parent)) return;
-            p.addParent(parent, fromEmptyReduction);
+            p.parents().add(parent);
+            if (p!=parent && !fromEmptyReduction) p.queueReductions(parent);
         }
-        private void newNode3(Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction, Phase start) {
+        private void newNode3(Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction) {
             do {
                 if (token != null && state.canShift(token)) break;
                 if (state.isAccepting()) break;
                 if (token==null) break;
-                int count = 0;
-                Parser.Table.Reduction r = null;
                 if (!state.canReduce(token)) return;
                 //if (count > 1) break;
                 //if (r.numPop == 0) break;
@@ -97,7 +96,7 @@ class GSS {
                 //return;
             } while(false);
 
-            Node n = new Node(parent, pending, state, start);  // ALLOC
+            Node n = new Node(parent, pending, state);  // ALLOC
             n.queueEmptyReductions();
             if (!fromEmptyReduction) n.queueReductions(parent);
         }
@@ -124,7 +123,7 @@ class GSS {
         }
 
         public void invoke(Parser.Table.State st, Forest result, Node n) {
-            next.newNode(n, result, st, true, this);
+            next.newNode(n, result, st, true);
         }
         private Phase next = null;
 
@@ -184,12 +183,6 @@ class GSS {
         /** a node in the GSS */
         public final class Node extends FastSet<Node> implements Invokable<Parser.Table.Reduction, Node, Node> {
 
-            public void addParent(Node parent, boolean fromEmptyReduction) {
-                if (parents().contains(parent)) return;
-                parents().add(parent);
-                if (this!=parent && !fromEmptyReduction) queueReductions(parent);
-            }
-
             private Forest.Ref holder = null;
             private boolean allqueued = false;
 
@@ -207,21 +200,11 @@ class GSS {
                 if (allqueued) return;
                 allqueued = true;
                 int where = parents().size();
-                /*
-                for(Parser.Table.Reduction r : state.getReductions(token))
-                    if (r.numPop > 0)
-                        r.reduce(this);
-                */
                 state.invokeReductions(token, this, this, null);
             }
 
             public void queueReductions(Node n2) {
                 if (!allqueued) { queueReductions(); return; }
-                /*
-                for(Parser.Table.Reduction r : state.getReductions(token))
-                    if (r.numPop > 0)
-                        r.reduce(this, n2);
-                */
                 state.invokeReductions(token, this, this, n2);
             }
 
@@ -231,24 +214,17 @@ class GSS {
                     return;
                 }
                 if (r.numPop==0) return;
-                if (n2==null) {
-                    r.reduce(n);
-                } else {
-                    r.reduce(n, n2);
-                }
+                if (n2==null) r.reduce(n);
+                else          r.reduce(n, n2);
             }
             public void queueEmptyReductions() {
                 if (!reducing) return;
-                /*
-                  for(Parser.Table.Reduction r : state.getReductions(token))
-                        if (r.numPop==0)
-                            r.reduce(this);
-                */
                 state.invokeReductions(token, this, null, null);
             }
 
-            private Node(Node parent, Forest pending, Parser.Table.State state, Phase start) {
+            private Node(Node parent, Forest pending, Parser.Table.State state) {
                 this.state = state;
+                Phase start = parent==null ? null : parent.phase();
                 if (pending != null) this.holder().merge(pending);
                 if (parent != null) parents().add(parent);
                 if (Phase.this.hash.get(code(state, start)) != null) throw new Error("severe problem!");
@@ -269,6 +245,6 @@ class GSS {
 
     /** this is something of a hack right now */
     private static long code(Parser.Table.State state, Phase start) {
-        return (((long)state.idx) << 32) | (start==null ? 0 : start.pos);
+        return (((long)state.idx) << 32) | (start==null ? 0 : (start.pos+1));
     }
 }
index 81b4597..4244d21 100644 (file)
@@ -37,7 +37,7 @@ public abstract class Parser<T extends Token, R> {
         GSS gss = new GSS();
         Token.Location loc = input.getLocation();
         GSS.Phase current = gss.new Phase(null, input.next(), loc);
-        current.newNode(null, null, pt.start, true, null);
+        current.newNode(null, null, pt.start, true);
         for(;;) {
             loc = input.getLocation();
             GSS.Phase next = gss.new Phase(current, input.next(), loc);
@@ -142,6 +142,10 @@ public abstract class Parser<T extends Token, R> {
                     if (p.element() != null && p.element() instanceof Atom)
                         state.shifts.addAll(state.gotoSetTerminals.subset(((Atom)p.element())));
                 }
+            for(State state : all_states.values()) {
+                state.oreductions = state.reductions.optimize();
+                state.oshifts = state.shifts.optimize();
+            }
         }
 
         /** a single state in the LR table and the transitions possible from it */
@@ -179,15 +183,15 @@ public abstract class Parser<T extends Token, R> {
             private           TopologicalBag<Token,State>     shifts              = new TopologicalBag<Token,State>();
             private           boolean                         accept              = false;
 
-            private VisitableMap<Token,State> oshifts = shifts;
-            //private TopologicalBag<Token,Reduction> reductions2 = reductions;
+            private VisitableMap<Token,State> oshifts = null;
+            private VisitableMap<Token,Reduction> oreductions = null;
 
             // Interface Methods //////////////////////////////////////////////////////////////////////////////
 
             public boolean             isAccepting()               { return accept; }
 
-            public boolean             canShift(Token t)           { return shifts.contains(t); }
-            public boolean             canReduce(Token t)          { return t==null ? eofReductions.size()>0 : reductions.has(t); }
+            public boolean             canShift(Token t)           { return oshifts.contains(t); }
+            public boolean             canReduce(Token t)          { return t==null ? eofReductions.size()>0 : oreductions.contains(t); }
 
             public Iterator<Position>  iterator()                  { return hs.iterator(); }
 
@@ -196,7 +200,7 @@ public abstract class Parser<T extends Token, R> {
             }
             public <B,C> void          invokeReductions(Token t, Invokable<Reduction,B,C> irbc, B b, C c) {
                 if (t==null) for(Reduction r : eofReductions) irbc.invoke(r, b, c);
-                else         reductions.invoke(t, irbc, b, c);
+                else         oreductions.invoke(t, irbc, b, c);
             }
 
             // Constructor //////////////////////////////////////////////////////////////////////////////
@@ -337,6 +341,7 @@ public abstract class Parser<T extends Token, R> {
             public void reduce(GSS.Phase.Node parent, GSS.Phase.Node onlychild) {
                 if (numPop<=0) throw new Error("called wrong form of reduce()");
                 int pos = numPop-1;
+                Forest old = holder[pos];
                 holder[pos] = parent.pending();
                 if (pos==0) {
                     System.arraycopy(holder, 0, position.holder, 0, holder.length);
@@ -344,23 +349,27 @@ public abstract class Parser<T extends Token, R> {
                 } else {
                     reduce(onlychild, pos-1, parent.phase());
                 }
+                holder[pos] = old;
             }
 
             // FIXME: this could be more elegant and/or cleaner and/or somewhere else
             private void reduce(GSS.Phase.Node parent, int pos, GSS.Phase target) {
+                Forest old = holder[pos];
                 holder[pos] = parent.pending();
                 if (pos==0) {
                     System.arraycopy(holder, 0, position.holder, 0, holder.length);
+                    for(int i=0; i<position.pos; i++) if (position.holder[i]==null) throw new Error("realbad");
                     Forest rex = position.rewrite(target.getLocation());
                     for(GSS.Phase.Node child : parent.parents()) finish(child, rex, target);
                 } else {
                     for(GSS.Phase.Node child : parent.parents()) reduce(child, pos-1, target);
                 }
+                holder[pos] = old;
             }
             private void finish(GSS.Phase.Node parent, Forest result, GSS.Phase target) {
                 State state = parent.state.gotoSetNonTerminals.get(position.owner());
                 if (state!=null)
-                    target.newNode(parent, result, state, numPop<=0, parent.phase());
+                    target.newNode(parent, result, state, numPop<=0);
             }
         }
     }
index ee3fd4b..83d9b6f 100644 (file)
@@ -114,7 +114,11 @@ public abstract class Sequence extends Element implements Iterable<Element> {
         final <T> Forest<T> rewrite(Token.Location loc) {
             if (this==firstp() && eps) return epsilonForm;
             eps = true;
-            for(int i=pos; i<elements.length; i++) if (holder[i]==null) holder[i] = elements[i].epsilonForm();
+            for(int i=0; i<pos; i++) if (holder[i]==null) throw new Error("realbad " + i);
+            for(int i=pos; i<elements.length; i++) {
+                if (holder[i]==null) holder[i] = elements[i].epsilonForm();
+                if (holder[i]==null) throw new Error("bad " + i);
+            }
             Forest<T> ret = Sequence.this.postReduce(loc, holder);
             for(int k=0; k<pos; k++) holder[k] = null; // to help GC
             if (this==firstp()) { if (epsilonForm==null) epsilonForm=new Forest.Ref(); epsilonForm.merge(ret); return epsilonForm; }
@@ -178,6 +182,7 @@ public abstract class Sequence extends Element implements Iterable<Element> {
         public Unwrap(Element[] e, HashSet<Sequence> and, HashSet<Sequence> not)                  { super(e, and, not); this.drops = null; }
         public Unwrap(Element[] e, boolean[] drops, HashSet<Sequence> and, HashSet<Sequence> not) { super(e, and, not); this.drops = drops; }
         public <T> Forest<T> postReduce(Token.Location loc, Forest<T>[] args) {
+            for(int i=0; i<args.length; i++) if (args[i]==null) throw new Error();
             if (drops==null) return Forest.create(loc, null, args, this, true, false);
             int count = 0;
             for(int i=0; i<drops.length; i++) if (!drops[i]) count++;
index bdfa380..b94613e 100644 (file)
@@ -40,7 +40,12 @@ public /*final*/ class FastSet<T> implements Iterator<T>, Iterable<T> {
     }
     public void add(T t, boolean check) {
         //if (check) for(Object o : this) if (o.equals(t)) return;
-        if (check) for(Object o : this) if (o==t) return;
+        if (check) {
+            if (only==t) return;
+            if (array != null)
+                for(int i=0; i<size; i++)
+                    if (array[i]==t) return;
+        }
         add(t);
     }
     public void add(T t) {
index 27157cd..6c538e6 100644 (file)
@@ -134,5 +134,49 @@ public class TopologicalBag<K,V> implements MapBag<Topology<K>,V>, VisitableMap<
             return ret;
         }
     }
+
+    public VisitableMap<K,V> optimize() {
+        ArrayList<Long> min_ = new ArrayList<Long>();
+        ArrayList<Long> max_ = new ArrayList<Long>();
+        ArrayList<Object[]> v_ = new ArrayList<Object[]>();
+        for(Topology<K> t : h.keySet()) {
+            ArrayList<V> al = new ArrayList<V>();
+            for(V vv : h.get(t)) al.add(vv);
+            Object[] vs = new Object[al.size()];
+            al.toArray(vs);
+            IntegerTopology it = (IntegerTopology)t;
+            for(Range r : it.getRanges()) {
+                min_.add(r.isMinNegInf() ? Long.MIN_VALUE : r.getMin());
+                max_.add(r.isMaxPosInf() ? Long.MAX_VALUE : r.getMax());
+                v_.add(vs);
+            }
+        }
+        final int size = v_.size();
+        final long[]     min = new long[size];     for(int i=0; i<min.length; i++) min[i]=min_.get(i);
+        final long[]     max = new long[size];     for(int i=0; i<max.length; i++) max[i]=max_.get(i);
+        final Object[][]   v = new Object[size][]; v_.toArray(v);
+        return new VisitableMap<K,V>() {
+            public boolean contains(K k) {
+                IntegerTopology.IntegerMappable im = (IntegerTopology.IntegerMappable)k;
+                int asint = im.toInt();
+                for(int i=0; i<size; i++)
+                    if (min[i] <= asint && max[i] >= asint && v[i].length > 0)
+                        return true;
+                return false;
+            }
+            public <B,C> void invoke(K k, Invokable<V,B,C> ivbc, B b, C c) {
+                IntegerTopology.IntegerMappable im = (IntegerTopology.IntegerMappable)k;
+                int asint = im.toInt();
+                for(int i=0; i<size; i++) {
+                    if (min[i] <= asint && max[i] >= asint) {
+                        Object[] arr = v[i];
+                        for(int j=0; j<arr.length; j++)
+                            ivbc.invoke((V)arr[j], b, c);
+                    }
+                }
+            }
+        };
+    }
+
     private final Iterable<V> emptyIterator = new EmptyIterator<V>();
 }
index ac0d1ea..7fab26b 100644 (file)
@@ -4,7 +4,6 @@ header
   comment  = my homepage is at
 
 == Introduction ==
-  this is the body adam@megacz.com text
+  this is the body adam@megacz.com
+
 
-  the following paragraph demonstrates verbatim stuff, as well as a
-  footnote ((like this)) because they are coool
index a249286..f0815a8 100644 (file)
@@ -272,59 +272,59 @@ testcase {
   q  ::= [a-z]++ => "q"
 }
 
-//testcase {
-//
-//    input "
-//
-//
-// while x>0
-//   while y>0
-//    foo()
-//     bar()
-//
-// while x>0
-//   while y>0
-//    foo()
-//   bar()
-//
-//
-//";
-//    output "smt:{while:{>:{{x} {0}} while:{>:{{y} {0}} sbb:{{f o o} {b a r}}}}}";
-//    output "smt:{while:{>:{{x} {0}} sbb:{while:{>:{{y} {0}} {f o o}} {b a r}}}}";
-//
-//indent  !::= ww
-//outdent !::= " "  outdent " "
-//           | " "  (~[]*)  "\n"
-//
-//any      !::= ~[]*
-//s         ::= any "\n\n" ww statement ww "\n\n" any => smt
-//ww       !::= sp*
-//ws       !::= sp**
-//sp        ::= " "
-//
-//block     ::= "\n" indent  blockBody
-//           &~ "\n" outdent ~[\ ] ~[]*
-//
-//blockBody ::= statement
-//            > statement blockBody /ws => "sbb"
-//
-//statement ::= call
-//            | ^"while" expr block /ws
-//
-//expr      ::= ident
-//            | call
-//            | expr ^">" expr   /ws
-//            | num
-//
-//call      ::= expr "()"        /ws
-//
-//num       ::= [0-9]++
-//
-//ident     ::= [a-z]++ &~ keyword
-//keyword   ::= "if" | "then" | "else" | "while"
-//
-//w         ::= " " | "\n" | "\r"
-//ws        ::= w*
-//
-//
-//}
+testcase {
+
+    input "
+
+
+ while x>0
+   while y>0
+    foo()
+     bar()
+
+ while x>0
+   while y>0
+    foo()
+   bar()
+
+
+";
+    output "smt:{while:{>:{{x} {0}} while:{>:{{y} {0}} sbb:{{f o o} {b a r}}}}}";
+    output "smt:{while:{>:{{x} {0}} sbb:{while:{>:{{y} {0}} {f o o}} {b a r}}}}";
+
+indent  !::= ww
+outdent !::= " "  outdent " "
+           | " "  (~[]*)  "\n"
+
+any      !::= ~[]*
+s         ::= any "\n\n" ww statement ww "\n\n" any => smt
+ww       !::= sp*
+ws       !::= sp**
+sp        ::= " "
+
+block     ::= "\n" indent  blockBody
+           &~ "\n" outdent ~[\ ] ~[]*
+
+blockBody ::= statement
+            > statement blockBody /ws => "sbb"
+
+statement ::= call
+            | ^"while" expr block /ws
+
+expr      ::= ident
+            | call
+            | expr ^">" expr   /ws
+            | num
+
+call      ::= expr "()"        /ws
+
+num       ::= [0-9]++
+
+ident     ::= [a-z]++ &~ keyword
+keyword   ::= "if" | "then" | "else" | "while"
+
+w         ::= " " | "\n" | "\r"
+ws        ::= w*
+
+
+}
index 5926194..99bab83 100644 (file)
@@ -47,11 +47,10 @@ SectionHeaderBody ::=  "=" SectionHeaderBody "="
 
 kv         ::= word "=" text /ws => kv1
 
-num !::= [0-9]++ => "stringify"
 Paragraph  ::= { "\"\"" ws text }        => "blockquote"
              > { "*" " " ws text }       => "ul"
              > { "#" " " ws text }       => "ol"
-             > { num " " ws text }       => "ol"
+             > { num " " ws text => "ol" }
              > { "---" "-"* }            => "hr"
              > { text }                  => "p"
 
@@ -100,12 +99,12 @@ method     ::= [+\-.a-z0-9]+
 port       ::= [0-9]+
 
 domain     ::= part +/ "."
-part       ::= [a-zA-Z0-9\-]++ => "stringify"   // interesting use of boolean grammars
+part       ::= [A-Za-z0-9\-]++ => "stringify"
 //            &~ ([\-0-9] ~[]* | ~[]* [\-0-9])
 
 email      ::= username "@" host      => email
-host       ::= [0-9]+ "." [0-9]+ "." [0-9]+ "." [0-9]+ => "ip"
-             | domain
+host       ::= domain
+             | [0-9]+ "." [0-9]+ "." [0-9]+ "." [0-9]+ => "ip"
 
 
 
@@ -124,7 +123,8 @@ escaped  ::= "\\n" => "\n"
 // Chars ///////////////////////////////////////////////////////////////
 
 alpha    ::= [a-zA-Z]
-num      ::= [0-9]
+num     !::= [0-9]++ => "stringify"
+//num      ::= [0-9]
 alphanum ::= [a-zA-Z0-9]
 sym      ::= ~[a-zA-Z0-9\ \r\n]