void run(PrintWriter out, String... args) throws IOException {
      JavaCompiler c = ToolProvider.getSystemJavaCompiler();
      StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);

      // DPrinter options
      final Set<TaskEvent.Kind> before = EnumSet.noneOf(TaskEvent.Kind.class);
      final Set<TaskEvent.Kind> after = EnumSet.noneOf(TaskEvent.Kind.class);
      boolean showPositions = false;
      boolean showSource = false;
      boolean showTreeSymbols = false;
      boolean showTreeTypes = false;
      boolean showEmptyItems = true;
      boolean showNulls = true;

      // javac options
      Collection<String> options = new ArrayList<String>();
      Collection<File> files = new ArrayList<File>();
      String classpath = null;
      String classoutdir = null;

      final Handler h = getHandlers().get(args[0]);
      if (h == null) throw new IllegalArgumentException(args[0]);

      for (int i = 1; i < args.length; i++) {
        String arg = args[i];
        if (arg.equals("-before") && i + 1 < args.length) {
          before.add(getKind(args[++i]));
        } else if (arg.equals("-after") && i + 1 < args.length) {
          after.add(getKind(args[++i]));
        } else if (arg.equals("-showPositions")) {
          showPositions = true;
        } else if (arg.equals("-showSource")) {
          showSource = true;
        } else if (arg.equals("-showTreeSymbols")) {
          showTreeSymbols = true;
        } else if (arg.equals("-showTreeTypes")) {
          showTreeTypes = true;
        } else if (arg.equals("-hideEmptyLists")) {
          showEmptyItems = false;
        } else if (arg.equals("-hideNulls")) {
          showNulls = false;
        } else if (arg.equals("-classpath") && i + 1 < args.length) {
          classpath = args[++i];
        } else if (arg.equals("-d") && i + 1 < args.length) {
          classoutdir = args[++i];
        } else if (arg.startsWith("-")) {
          int n = c.isSupportedOption(arg);
          if (n < 0) throw new IllegalArgumentException(arg);
          options.add(arg);
          while (n > 0) options.add(args[++i]);
        } else if (arg.endsWith(".java")) {
          files.add(new File(arg));
        }
      }

      if (classoutdir != null) {
        fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir)));
      }

      if (classpath != null) {
        Collection<File> path = new ArrayList<File>();
        for (String p : classpath.split(File.pathSeparator)) {
          if (p.isEmpty()) continue;
          File f = new File(p);
          if (f.exists()) path.add(f);
        }
        fm.setLocation(StandardLocation.CLASS_PATH, path);
      }
      Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);

      JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos);
      final Trees trees = Trees.instance(task);

      final DPrinter dprinter = new DPrinter(out, trees);
      dprinter
          .source(showSource)
          .emptyItems(showEmptyItems)
          .nulls(showNulls)
          .positions(showPositions)
          .treeSymbols(showTreeSymbols)
          .treeTypes(showTreeTypes);

      if (before.isEmpty() && after.isEmpty()) {
        if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes)
          after.add(TaskEvent.Kind.PARSE);
        else after.add(TaskEvent.Kind.ANALYZE);
      }

      task.addTaskListener(
          new TaskListener() {
            public void started(TaskEvent e) {
              if (before.contains(e.getKind())) handle(e);
            }

            public void finished(TaskEvent e) {
              if (after.contains(e.getKind())) handle(e);
            }

            private void handle(TaskEvent e) {
              JCCompilationUnit unit = (JCCompilationUnit) e.getCompilationUnit();
              switch (e.getKind()) {
                case PARSE:
                case ENTER:
                  h.handle(e.getSourceFile().getName(), unit, unit, dprinter);
                  break;

                default:
                  TypeElement elem = e.getTypeElement();
                  h.handle(elem.toString(), unit, (JCTree) trees.getTree(elem), dprinter);
                  break;
              }
            }
          });

      task.call();
    }