     [ new RegExp("^.*/shell/.*$"),
      new RegExp("^.*/extensions/ST_.*$"),
      new RegExp("^.*/extensions/JavaGlue.*$"),
+     new RegExp("^.*/eval/.*$"),
      new RegExp("^.*/MMgc/GCTests.*$")];
 
 class LineInfo
 {
-    function LineInfo(_derived, _base, _filename, _lineno) {
+    function LineInfo(_derived, _base, _isExact, _filename, _lineno) {
         derived = _derived;
         base = _base;
+        isExact = _isExact;
         filename = _filename;
         lineno = _lineno;
     }
+
+    public function toString() {
+        return "derived=" + derived + ", base=" + base + ", filename=" + filename + ", lineno=" + lineno + ", defcount=" + defcount;
+    }
+
     var derived;            // name of the class being defined
     var base;               // name of its base class
+    var isExact;            // true iff the class is exactly traced
     var filename;           // file where we found the definition of 'derived'
     var lineno;             // line where we found the definition of 'derived'
     var baseref = null;     // reference to the LineInfo for the base class
     var subrefs = [];       // list of known subclasses
     var destructor = false; // true if we believe this has a destructor
+    var defcount = 0;       // number of definitions
+    var otherlines = [];    // for in-tree lines beyond the first: locations of definition: { filename:x, lineno:n }
+    var exolines = [];      // for out-of-tree lines: locations of definition: { filename:x, lineno:n }
+    var external = false;   // true if there are definitions of the 'derived' name not within the tree
 }
 
 main(System.argv);

                    }
                }
            }
            if (l.indexOf("class") != -1) {
                if ((result = l.match(re1)) || (result = l.match(re2))) {
                    var derived = result[1];
                    var base = stripNamespaces(result[2]);
                    all_lines.push(new LineInfo(derived,base,fn,i+1));
                }
            }
            else if (!ignore && l.indexOf("~") != -1) {
                if (result = l.match(red)) {
                    probable_destructors[result[1]] = true;
                }
            }
        }

        var lines = readFile(fn);
        var ignore = false;
        var ignorelevel = 0;

        for ( var i=0 ; i < lines.length ; i++ ) {
            var l = lines[i];
            var result;
