org.antlr.eclipse.core.builder.AntlrBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.antlr.eclipse.core.builder.AntlrBuilder.java

Source

/**
 * <small>
 * <p><i>Copyright (C) 2005 Torsten Juergeleit, 
 * All rights reserved. </i></p>
 * 
 * <p>USE OF THIS CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS
 * AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES
 * INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
 * OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS
 * OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
 * BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND
 * THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES
 * INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
 * 
 * <p>This Content is Copyright (C) 2005 Torsten Juergeleit, 
 * and is provided to you under the terms and conditions of the Common Public 
 * License Version 1.0 ("CPL"). A copy of the CPL is provided with this Content 
 * and is also available at 
 *     <a href="http://www.eclipse.org/legal/cpl-v10.html">
 *         http://www.eclipse.org/legal/cpl-v10.html </a>.
 * 
 * For purposes of the CPL, "Program" will mean the Content.</p>
 * 
 * <p>Content includes, but is not limited to, source code, object code,
 * documentation and any other files in this distribution.</p>
 * 
 * </small>
 */
package org.antlr.eclipse.core.builder;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.antlr.eclipse.core.AntlrCorePlugin;
import org.antlr.eclipse.core.AntlrNature;
import org.antlr.eclipse.core.properties.SettingsPersister;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;

import antlr.AntlrTool;

/**
 * An eclipse builder to compile ANTLR grammars
 */
public class AntlrBuilder extends IncrementalProjectBuilder implements IStreamListener {
    /** the builder id */
    public static final String BUILDER_ID = AntlrCorePlugin.PLUGIN_ID + ".antlrbuilder";
    /** the builder debug id */
    public static final String DEBUG_OPTION = AntlrCorePlugin.PLUGIN_ID + "/builder/debug";
    /** are we debugging the builder? */
    public static boolean DEBUG = false;

    private IFile fFile;
    private String fOutput;
    private PrintStream fOriginalOut;
    private PrintStream fOriginalErr;

    /** the persistent option that indicates that a generated file should have warnings cleared */
    public static final QualifiedName CLEAN_WARNINGS = new QualifiedName(AntlrCorePlugin.PLUGIN_ID,
            SettingsPersister.CLEAN_WARNINGS);

    /** the persistent option that indicates that a generated file should have warnings cleared */
    public static final QualifiedName INSTALL_SMAP = new QualifiedName(AntlrCorePlugin.PLUGIN_ID,
            SettingsPersister.SMAP_PROPERTY);

    /** the persistent option that attaches a grammar name to a file it generated */
    public static final QualifiedName GRAMMAR_ECLIPSE_PROPERTY = new QualifiedName(AntlrCorePlugin.PLUGIN_ID,
            SettingsPersister.GRAMMAR_PROPERTY);

    /** the persistent option that attaches command line options to generated file */
    public static final QualifiedName COMMAND_LINE_OPTIONS_PROPERTY = new QualifiedName(AntlrCorePlugin.PLUGIN_ID,
            "commandLineOptions");

    /**
     * Create a builder
     */
    public AntlrBuilder() {
        DEBUG = AntlrCorePlugin.isDebug(DEBUG_OPTION);
    }

    /** {@inheritDoc} */
    @Override
    protected void clean(IProgressMonitor monitor) throws CoreException {
        // delete all derived resources that have a GRAMMAR option on them
        getProject().accept(new CleaningVisitor(monitor, null));
    }

    /** Simple visitor collecting files with .g extension */
    private class GrammarCollectorVisitor implements IResourceVisitor {
        private ArrayList<IFile> files = new ArrayList<IFile>();

        public ArrayList<IFile> getFiles() {
            return files;
        }

        @Override
        public boolean visit(IResource resource) throws CoreException {
            if (resource instanceof IFile) {
                IFile file = (IFile) resource;
                if (file.getName().endsWith(".g")) {
                    files.add(file);
                }
            }

            return true;
        }

    }

    /**
     * Walks the super grammars and imported vocabularies of the provided file.
     * And returns the topological ordering of the grammars.
     * 
     * @param file the file to process
     * @param result the topologically ordered list of grammars.
     * */
    private void depthWalk(final IFile file, LinkedList<IFile> result) {
        HashMap<String, HashMap<String, String>> map = SettingsPersister.readSettings(file.getProject());
        // Get super grammars from grammar properties
        String superGrammars = SettingsPersister.get(map, file, SettingsPersister.SUPER_GRAMMARS_PROPERTY);
        String importVocabularies = SettingsPersister.get(map, file,
                SettingsPersister.IMPORT_VOCABULARIES_PROPERTY);

        if (superGrammars == null || superGrammars.trim().isEmpty()) {
            // Try to get // -glib parameter from comment in .g file. This
            // enables sharing in a team project without local reconfiguration
            String localSuperGrammar = extractGlibComment(file);
            if (localSuperGrammar != null) {
                superGrammars = convertFolderRelatedPath(localSuperGrammar);
            }
        }

        if (superGrammars == null && importVocabularies == null) {
            return;
        }
        //tokenize && walk
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        if (superGrammars != null) {
            StringTokenizer tokenizer = new StringTokenizer(superGrammars, ";");
            while (tokenizer.hasMoreTokens()) {
                String grammar = tokenizer.nextToken();
                IResource resource = root.findMember(grammar);
                if (resource != null && resource instanceof IFile) {
                    IFile superFile = (IFile) resource;
                    if (!result.contains(superFile)) {
                        depthWalk(superFile, result);
                        result.add(superFile);
                    }
                }
            }
        }
        if (importVocabularies != null) {
            StringTokenizer tokenizer = new StringTokenizer(importVocabularies, ";");
            while (tokenizer.hasMoreTokens()) {
                String grammar = tokenizer.nextToken();
                IResource resource = root.findMember(grammar);
                if (resource != null && resource instanceof IFile) {
                    IFile superFile = (IFile) resource;
                    if (!result.contains(superFile)) {
                        depthWalk(superFile, result);
                        result.add(superFile);
                    }
                }
            }
        }
    }

    /**
     * Calculate the topological ordering of grammars.
     * 
     * @param files the list of grammar file to process
     * 
     * @return the topologically ordered list of grammars.
     * */
    private LinkedList<IFile> topologicalOrdering(ArrayList<IFile> files) {
        LinkedList<IFile> result = new LinkedList<IFile>();
        for (IFile file : files) {
            depthWalk(file, result);
            if (!result.contains(file)) {
                result.add(file);
            }
        }

        return result;
    }

    /** {@inheritDoc} */
    @Override
    protected IProject[] build(int aKind, Map<String, String> anArgs, IProgressMonitor aMonitor)
            throws CoreException {
        IProject project = getProject();

        if (!AntlrNature.hasNature(project)) {
            return null;
        }
        if (aKind == FULL_BUILD) {

            GrammarCollectorVisitor visitor = new GrammarCollectorVisitor();
            project.accept(visitor);
            ArrayList<IFile> files = visitor.getFiles();

            LinkedList<IFile> orderedFiles = topologicalOrdering(files);

            for (int i = 0; i < orderedFiles.size(); i++) {
                IFile file = orderedFiles.get(i);
                compileFile(file, aMonitor);
            }
        } else {
            IResourceDelta delta = getDelta(project);
            delta.accept(new DeltaVisitor(aMonitor));
        }
        return null;
    }

    /** {@inheritDoc} */
    @Override
    public void streamAppended(String aText, Object aStream) {
        if (DEBUG) {
            fOriginalOut.println("ANTLR output: " + aText);
        }
        int line = 0;
        String message = null;
        int severity = 0;

        // First check for messages with header "<file>|<line>|<column>"
        StringTokenizer st = new StringTokenizer(aText, "|");
        if (st.countTokens() > 3) {
            st.nextToken(); // file
            line = Integer.parseInt(st.nextToken());
            Integer.parseInt(st.nextToken()); // column
            message = st.nextToken();
            while (st.hasMoreTokens()) {
                message += st.nextToken();
            }
            if (message.startsWith("warning:")) {
                severity = IMarker.SEVERITY_WARNING;
                message = message.substring(8);
            } else {
                severity = IMarker.SEVERITY_ERROR;
            }
            message = message.replace('\t', ' ').trim();

            // Then check for messages without header
        } else if (aText.startsWith("panic: ")) {
            message = aText.substring(7);
            severity = IMarker.SEVERITY_ERROR;
        } else if (aText.startsWith("error: ")) {
            message = aText.substring(7);
            severity = IMarker.SEVERITY_ERROR;
        } else if (aText.startsWith("warning: ")) {
            severity = IMarker.SEVERITY_WARNING;
            message = aText.substring(9);
        } else {
            if (DEBUG) {
                fOriginalOut.println("Unhandled ANTLR output: " + aText);
            }
        }

        // If valid error/warning message found then create problem marker
        if (message != null) {
            createProblemMarker(line, message, severity);
        }
    }

    private void createProblemMarker(int aLine, String aMessage, int aSeverity) {
        try {
            IMarker marker = fFile.createMarker(IMarker.PROBLEM);
            marker.setAttribute(IMarker.MESSAGE, aMessage);
            marker.setAttribute(IMarker.SEVERITY, aSeverity);
            if (aLine > 0) {
                marker.setAttribute(IMarker.LINE_NUMBER, aLine);
            }
        } catch (CoreException e) {
            AntlrCorePlugin.log(e);
        }
    }

    private class DeltaVisitor implements IResourceDeltaVisitor {
        private IProgressMonitor fMonitor;

        /**
         * Create a delta visitor
         * @param aMonitor A progress monitor
         */
        public DeltaVisitor(IProgressMonitor aMonitor) {
            fMonitor = aMonitor;
        }

        /** {@inheritDoc} */
        @Override
        public boolean visit(IResourceDelta aDelta) {
            boolean visitChildren = false;

            IResource resource = aDelta.getResource();
            if (resource instanceof IProject) {

                // Only check projects with ANTLR nature
                IProject project = (IProject) resource;
                visitChildren = AntlrNature.hasNature(project);
            } else if (resource instanceof IFolder) {
                visitChildren = true;
            } else if (resource instanceof IFile) {

                // Only check ANTLR grammar files
                IFile file = (IFile) resource;
                String ext = file.getFileExtension();
                if (file.exists() && ext != null && ext.equals("g")) {
                    switch (aDelta.getKind()) {
                    case IResourceDelta.ADDED:
                    case IResourceDelta.CHANGED:
                        compileFile(file, fMonitor);
                        visitChildren = true;
                        break;

                    case IResourceDelta.REMOVED:
                        // delete the old generated files for this grammar
                        try {
                            String grammarFileName = file.getProjectRelativePath().toString();
                            file.getProject().accept(new CleaningVisitor(fMonitor, grammarFileName));
                        } catch (CoreException e) {
                            AntlrCorePlugin.log(e);
                        }
                        visitChildren = true;
                        break;
                    }
                }
            }
            return visitChildren;
        }
    }

    /**
     * Compile a grammar
     * @param aFile The grammar file to compile
     * @param aMonitor A progress monitor
     */
    public void compileFile(IFile aFile, IProgressMonitor aMonitor) {
        String grammarFileName = aFile.getProjectRelativePath().toString();
        try {
            // delete the old generated files for this grammar
            aFile.getProject().accept(new CleaningVisitor(aMonitor, grammarFileName));

            // if it's in a java project, only build it if it's in a source dir
            if (aFile.getProject().hasNature(JavaCore.NATURE_ID)) {
                IProject project = aFile.getProject();
                IJavaProject javaProject = JavaCore.create(project);
                IPath path = aFile.getFullPath();
                boolean ok = false;
                IClasspathEntry[] resolvedClasspath = javaProject.getResolvedClasspath(true);
                for (int i = 0; i < resolvedClasspath.length; i++) {
                    IClasspathEntry entry = resolvedClasspath[i];

                    if (entry.getEntryKind() != IClasspathEntry.CPE_SOURCE)
                        continue;

                    IPath entryPath = entry.getPath();
                    if (entryPath.isPrefixOf(path)) {
                        ok = true;
                        break;
                    }
                }
                if (!ok) {
                    return;
                }
            }
        } catch (CoreException e1) {
            e1.printStackTrace();
        }

        fFile = aFile;

        aMonitor.beginTask(
                AntlrCorePlugin.getFormattedMessage("AntlrBuilder.compiling", aFile.getFullPath().toString()), 4);

        // Remove all markers from this file
        try {
            aFile.deleteMarkers(null, true, IResource.DEPTH_INFINITE);
        } catch (CoreException e) {
            AntlrCorePlugin.log(e);
        }

        // Prepare arguments for ANTLR compiler
        // read the settings for this grammar
        HashMap<String, HashMap<String, String>> map = SettingsPersister.readSettings(aFile.getProject());

        ArrayList<String> args = createArguments(map, aFile);
        if (DEBUG) {
            System.out.println("Compiling ANTLR grammar '" + aFile.getName() + "': arguments=" + args);
        }

        // Monitor system out and err
        fOriginalOut = System.out;
        fOriginalErr = System.err;
        System.setOut(new PrintStream(new MonitoredOutputStream(this)));
        System.setErr(new PrintStream(new MonitoredOutputStream(this)));

        try {
            // Compile ANTLR grammar file
            AntlrTool tool = new AntlrTool();
            if (!tool.preprocess(args.toArray(new String[args.size()]))) {
                try {
                    aMonitor.worked(1);
                    if (!tool.parse()) {
                        aMonitor.worked(1);
                        if (!tool.generate()) {
                            aMonitor.worked(1);
                            refreshFolder(map, tool, args, aFile, grammarFileName,
                                    ResourcesPlugin.getWorkspace().getRoot().findMember(fOutput), aMonitor,
                                    tool.getSourceMaps());
                        } else {

                            // If errors during generate then delete all
                            // generated files
                            deleteFiles(tool, aFile.getParent(), aMonitor);
                        }
                        aMonitor.worked(1);
                    }
                } catch (CoreException e) {
                    AntlrCorePlugin.log(e);
                }
            }

        } catch (Throwable e) {
            if (!(e instanceof SecurityException)) {
                AntlrCorePlugin.log(e);
            }
        } finally {
            System.setOut(fOriginalOut);
            System.setErr(fOriginalErr);
            aMonitor.done();
        }
    }

    /**
     * Returns list of commandline arguments for ANTLR compiler.
     * @param map the saved antlr-eclipse settings for this project
     * @param file The grammar file to parse
     * @return a list of command-line arguments
     */
    private ArrayList<String> createArguments(HashMap<String, HashMap<String, String>> map, IFile file) {
        ArrayList<String> args = new ArrayList<String>();

        AntlrCorePlugin.getDefault().upgradeOldSettings(file, map);

        fOutput = SettingsPersister.get(map, file, SettingsPersister.OUTPUT_PROPERTY);
        // Prepare absolute output path (-o)
        String outputPath = null;
        if (fOutput != null && fOutput.trim().length() > 0) {
            outputPath = convertRootRelatedPath(fOutput);
        }
        if (outputPath == null) {
            fOutput = fFile.getParent().getFullPath().toOSString();
            outputPath = fFile.getParent().getLocation().toOSString();
        }
        args.add("-o");
        args.add(outputPath);

        // Get boolean options from grammar properties
        addBooleanGrammarProperty(map, file, SettingsPersister.DEBUG_PROPERTY, "-debug", null, args, false);
        addBooleanGrammarProperty(map, file, SettingsPersister.HTML_PROPERTY, "-html", null, args, false);
        addBooleanGrammarProperty(map, file, SettingsPersister.DOCBOOK_PROPERTY, "-docbook", null, args, false);
        addBooleanGrammarProperty(map, file, SettingsPersister.DIAGNOSTIC_PROPERTY, "-diagnostic", null, args,
                false);
        addBooleanGrammarProperty(map, file, SettingsPersister.TRACE_PROPERTY, "-trace", null, args, false);
        addBooleanGrammarProperty(map, file, SettingsPersister.TRACE_PARSER_PROPERTY, "-traceParser", null, args,
                false);
        addBooleanGrammarProperty(map, file, SettingsPersister.TRACE_LEXER_PROPERTY, "-traceLexer", null, args,
                false);
        addBooleanGrammarProperty(map, file, SettingsPersister.TRACE_TREE_PARSER_PROPERTY, "-traceTreeParser", null,
                args, false);
        addBooleanGrammarProperty(map, file, SettingsPersister.SMAP_PROPERTY, "-smap", null, args, true);

        // Get super grammars from grammar properties
        String superGrammars = SettingsPersister.get(map, file, SettingsPersister.SUPER_GRAMMARS_PROPERTY);

        // Prepare optional super grammar(s) (-glib)
        // Can be defined in two ways : in a property dialog OR
        // inside the grammar using a comment "// -glib <file in same folder>" 
        if (superGrammars != null && superGrammars.trim().length() > 0) {
            superGrammars = convertRootRelatedPathList(superGrammars);
            if (superGrammars != null) {
                args.add("-glib");
                args.add(superGrammars);
            }
        } else {
            // Try to get // -glib parameter from comment in .g file. This
            // enables sharing in a team project without local reconfiguration
            String localSuperGrammar = extractGlibComment(fFile);
            if (localSuperGrammar != null) {
                localSuperGrammar = convertFolderRelatedPath(localSuperGrammar);
                if (localSuperGrammar != null) {
                    args.add("-glib");
                    args.add(localSuperGrammar);
                }
            }
        }

        // Prepare ANTLR grammar file which needs to be compiled
        args.add(fFile.getLocation().toOSString());
        return args;
    }

    private void addBooleanGrammarProperty(HashMap<String, HashMap<String, String>> map, IResource grammar,
            String propertyName, String option, String option2, ArrayList<String> args, boolean defaultValue) {
        boolean value;
        String stringValue = SettingsPersister.get(map, grammar, propertyName);
        if (stringValue == null)
            value = defaultValue;
        else
            value = "true".equalsIgnoreCase(stringValue);
        if (value) {
            args.add(option);
            if (option2 != null)
                args.add(option2);
        }
    }

    /**
     * Converts given path (related to workspace root) to an absolute path.
     * @param aPath The path to convert
     * @return The converted path
     */
    private String convertRootRelatedPath(String aPath) {
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        IResource resource = root.findMember(aPath);
        if (resource == null) {
            createProblemMarker(0, AntlrCorePlugin.getFormattedMessage("AntlrTool.error.noGrammarFile", aPath),
                    IMarker.SEVERITY_ERROR);
        }
        return (resource != null ? resource.getLocation().toOSString() : null);
    }

    /**
     * Converts given list of paths (related to workspace root) to a new list
     * with absolute paths (delimited by ';').
     * @param aPathList The paths to convert
     * @return The converted paths
     */
    private String convertRootRelatedPathList(String aPathList) {
        StringBuffer list = new StringBuffer();
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        StringTokenizer tokenizer = new StringTokenizer(aPathList, ";");
        while (tokenizer.hasMoreTokens()) {
            String grammar = tokenizer.nextToken();
            IResource resource = root.findMember(grammar);
            if (resource != null) {
                list.append(resource.getLocation().toOSString());
                if (tokenizer.hasMoreTokens()) {
                    list.append(';');
                }
            } else {
                createProblemMarker(0,
                        AntlrCorePlugin.getFormattedMessage("AntlrTool.error.noGrammarFile", grammar),
                        IMarker.SEVERITY_ERROR);
            }
        }
        return list.toString();
    }

    /**
     * Converts given path (related to folder of grammar file) to an absolute
     * path.
     * @param aPath The path to convert
     * @return The converted paths
     */
    private String convertFolderRelatedPath(String aPath) {
        IResource resource = fFile.getParent().findMember(aPath.toString());
        if (resource == null) {
            createProblemMarker(0, AntlrCorePlugin.getFormattedMessage("AntlrTool.error.noGrammarFile", aPath),
                    IMarker.SEVERITY_ERROR);
        }
        return (resource != null ? resource.getLocation().toOSString() : null);
    }

    private void deleteFiles(AntlrTool aTool, IContainer aFolder, IProgressMonitor aMonitor) {
        Iterator<String> files = aTool.files();
        while (files.hasNext()) {
            String fileName = files.next();
            if (DEBUG) {
                fOriginalOut.println("Deleting ANTLR generated file '" + fileName + "'");
            }
            IResource file = aFolder.findMember(fileName);
            if (file != null) {
                aMonitor.subTask(AntlrCorePlugin.getFormattedMessage("AntlrBuilder.deleting", fileName));
                try {
                    file.delete(true, aMonitor);
                } catch (CoreException e) {
                    AntlrCorePlugin.log(e);
                }
            }
        }
    }

    private void refreshFolder(HashMap<String, HashMap<String, String>> map, AntlrTool aTool,
            ArrayList<String> args, IFile grammarFile, String grammarFileName, IResource aFolder,
            IProgressMonitor aMonitor, Map<String, Map<Integer, List<Integer>>> sourceMaps) {
        aMonitor.subTask(
                AntlrCorePlugin.getFormattedMessage("AntlrBuilder.refreshing", aFolder.getFullPath().toString()));
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        IContainer folder = root.getContainerForLocation(aFolder.getLocation());
        if (DEBUG) {
            fOriginalOut.println("Refreshing output folder '" + folder.getFullPath() + "'");
        }
        try {
            StringBuffer argString = new StringBuffer();
            for (Iterator<String> i = args.iterator(); i.hasNext();) {
                String arg = i.next();
                argString.append(arg);
                argString.append("|");
            }
            ArrayList<IFile> compilationUnitFiles = new ArrayList<IFile>();
            Iterator<String> files = aTool.files();
            while (files.hasNext()) {
                String fileName = files.next();
                if (DEBUG) {
                    fOriginalOut.println("ANTLR generated file '" + fileName + "'");
                }
                IFile file = folder.getFile(new Path(fileName));
                file.refreshLocal(IResource.DEPTH_ZERO, aMonitor);
                // SASSAS check if file is being edited - if so, refresh
                file.setDerived(true);
                String cleanWarnings = SettingsPersister.get(map, grammarFile, SettingsPersister.CLEAN_WARNINGS);
                String installSmap = SettingsPersister.get(map, grammarFile, SettingsPersister.SMAP_PROPERTY);
                file.setPersistentProperty(CLEAN_WARNINGS, cleanWarnings);
                file.setPersistentProperty(INSTALL_SMAP, installSmap);
                file.setPersistentProperty(GRAMMAR_ECLIPSE_PROPERTY, grammarFileName);
                file.setPersistentProperty(COMMAND_LINE_OPTIONS_PROPERTY, argString.toString());
                if (fileName.endsWith(".java")) {
                    compilationUnitFiles.add(file);
                    Map<Integer, List<Integer>> sourceMap = sourceMaps.get(file.getName());

                    // add source mappings to the generated file
                    if (sourceMap != null)
                        for (Iterator<Integer> i = sourceMap.keySet().iterator(); i.hasNext();) {
                            Integer sourceLine = i.next();
                            List<Integer> targetLines = sourceMap.get(sourceLine);
                            for (Iterator<Integer> j = targetLines.iterator(); j.hasNext();) {
                                Integer targetLine = j.next();
                                IMarker marker = file.createMarker(AntlrCorePlugin.SOURCE_MAPPING_MARKER);
                                marker.setAttribute(AntlrCorePlugin.GRAMMAR_LINE_ATTRIBUTE, sourceLine);
                                marker.setAttribute(AntlrCorePlugin.GENERATED_LINE_ATTRIBUTE, targetLine);
                            }
                        }
                }
            }
            // WORK-IN-PROGRESS -- NON FUNCTIONAL
            //         if (!compilationUnitFiles.isEmpty()) {
            //            // find "end of imports" marker in generated code:
            //                     // $$END-OF-ANTLR-GENERATED-IMPORTS$$
            //            int[] oldImportEnds = findEndOfImports(compilationUnitFiles);
            //
            //            MultiStatus status = new MultiStatus(AntlrCorePlugin.PLUGIN_ID, 0, "", null);
            //            new ImportOrganizer().organizeImports(compilationUnitFiles, status, aMonitor);
            //            if (status.getSeverity() != IStatus.OK)
            //               AntlrCorePlugin.log(status);
            //            for (Iterator i = compilationUnitFiles.iterator(); i.hasNext();) {
            //               IFile file = (IFile)i.next();
            //               file.setDerived(true);
            //            }
            //            
            //            // find "end of imports" markers after the organize imports
            //            int[] newImportEnds = findEndOfImports(compilationUnitFiles);
            //            
            //            // adjust the smap files based on the offsets
            //            adjustSmapFiles(compilationUnitFiles, oldImportEnds, newImportEnds);
            //         }
        } catch (OperationCanceledException e) {
            // TODO what to do with cancel?
        } catch (Exception e) {
            AntlrCorePlugin.log(e);
        }
    }

    // WORK-IN-PROGRESS -- NON FUNCTIONAL
    //   /**
    //    * Adjust the smap line definitions based on line offsets
    //    * @param compilationUnitFiles the generated java files
    //    * @param oldImportEnds the old location of the "end of imports" marker
    //    * @param newImportEnds the new location of the "end of imports" marker
    //    */
    //   private void adjustSmapFiles(List compilationUnitFiles, int[] oldImportEnds, int[] newImportEnds) {
    //      int n = 0;
    //      for (Iterator i = compilationUnitFiles.iterator(); i.hasNext(); n++) {
    //         IFile file = (IFile)i.next();
    //         // skip token type definition files
    //         if (file.getName().endsWith("TokenTypes.java"))
    //            continue;
    //
    //         IPath smapLocation = file.getLocation().removeFileExtension().addFileExtension(".smap");
    //         // strip ".java" from the file name and add ".smap"
    //         System.out.println(smapLocation.toFile());
    //      }
    //   }
    //
    //   /**
    //    * Determine where the "end of imports" marker in the generated code is
    //    * @param compilationUnitFiles the file to process
    //    * @return an array of line numbers
    //    */
    //   private int[] findEndOfImports(List compilationUnitFiles) {
    //      int[] endOfImports = new int[compilationUnitFiles.size()];
    //      int n = 0;
    //      for (Iterator i = compilationUnitFiles.iterator(); i.hasNext(); n++) {
    //         IFile file = (IFile)i.next();
    //         // skip the token type definitions -- they don't have smaps
    //         if (file.getName().endsWith("TokenTypes.java"))
    //            continue;
    //         
    //         try {
    //            BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContents()));
    //            String line;
    //            while((line = reader.readLine()) != null) {
    //               if (line.startsWith("// $$END-OF-ANTLR-GENERATED-IMPORTS$$"))
    //                  break;
    //               endOfImports[n]++;
    //            }
    //         }
    //         catch (Exception e) {
    //            AntlrCorePlugin.log(e);
    //         }
    //      }
    //      return endOfImports;
    //   }

    /**
     * Try to get -glib parameter from the first single line comment in given
     * grammar file (// -glib <super grammar>).
     * This enables sharing in a team project without local reconfiguration.
     * @param aFile The grammar file
     * @return The glib comment
     */
    private String extractGlibComment(IFile aFile) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(aFile.getContents()));
            // Skip leading white spaces
            int c = reader.read();
            while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
                c = reader.read();
            }

            // Match leading "//"
            if (c == '/' && reader.read() == '/') {

                // Skip white spaces
                c = reader.read();
                while (c == ' ' || c == '\t') {
                    c = reader.read();
                }

                // Match "-glib"
                if (c == '-' && reader.read() == 'g' && reader.read() == 'l' && reader.read() == 'i'
                        && reader.read() == 'b' && reader.read() == ' ') {
                    // Skip white spaces
                    c = reader.read();
                    while (c == ' ' || c == '\t') {
                        c = reader.read();
                    }

                    // Use rest of line as relative path to super grammar
                    StringBuffer grammar = new StringBuffer();
                    while (c != '\n' && c != '\r') {
                        grammar.append((char) c);
                        c = reader.read();
                    }
                    return grammar.toString();
                }
            }
        } catch (Exception e) {
            AntlrCorePlugin.log(e);
        }
        return null;
    }
}