/*******************************************************************************
* Copyright (c) 2008 Scott Stanchfield, based on ANTLR-Eclipse plugin
* by Torsten Juergeleit.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors
* Torsten Juergeleit - original ANTLR Eclipse plugin
* Scott Stanchfield - modifications for ANTXR
*******************************************************************************/
package com.javadude.antxr;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import com.javadude.antxr.eclipse.core.AntxrCorePlugin;
/**
* Replacement ANTXR tool (main entry point) for Eclipse integration
*/
public class AntxrTool extends Tool {
private Map sourceMaps;
private String[] fPreprocessedArgs = null;
private LLkAnalyzer fAnalyzer = null;
private MakeGrammar fBehavior = null;
private ANTXRParser fParser = null;
private Vector<String> fFiles = new Vector<String>();
private Vector<PrintWriter> fWriters = new Vector<PrintWriter>();
/**
* Create the antxr tool instance
*/
public AntxrTool() {
setFileLineFormatter(new MarkerFormatter());
}
/**
* Returns iterator for all files created during last code generation.
* @return an iterator of all generated files
*/
public Iterator files() {
return fFiles.iterator();
}
/** {@inheritDoc} */
public void fatalError(String aMessage) {
System.err.println(FileLineFormatter.getFormatter().
getFormatString(null, -1, -1) + aMessage);
throw new IllegalStateException();
}
/** {@inheritDoc} */
public void error(String aMessage) {
System.err.println(FileLineFormatter.getFormatter().
getFormatString(null, -1, -1) + aMessage);
hasError = true;
}
/** {@inheritDoc} */
public void warning(String aMessage) {
System.err.println(FileLineFormatter.getFormatter().
getFormatString(null, -1, -1) + "warning: " +
aMessage);
}
/** {@inheritDoc} */
public void warning(String[] aMessageLines, String aFile, int aLine,
int aColumn) {
if (aMessageLines != null && aMessageLines.length != 0) {
StringBuffer message = new StringBuffer(aMessageLines[0]);
for (int i = 1; i < aMessageLines.length; i++) {
String line = aMessageLines[i];
int pos = 0;
while (Character.isWhitespace(line.charAt(pos))) {
pos++;
}
message.append(" ");
message.append(line.substring(pos));
}
System.err.println(FileLineFormatter.getFormatter().
getFormatString(aFile, aLine, aColumn) +
"warning: " + message.toString());
}
}
/** {@inheritDoc} */
public void toolError(String aMessage) {
System.err.println(FileLineFormatter.getFormatter().
getFormatString(null, -1, -1) + aMessage);
}
/** {@inheritDoc} */
public PrintWriter openOutputFile(String aFileName) throws IOException {
if (!fFiles.contains(aFileName)) {
fFiles.add(aFileName);
}
PrintWriter writer = new PrintWriter(new FileWriter(outputDir +
System.getProperty("file.separator") + aFileName));
fWriters.add(writer);
return writer;
}
/**
* Perform preprocessing on the grammar file.
* Can only be called from main().
* @param anArgs the command-line arguments passed to main()
* @return true if there was an error, false otherwise
*/
public boolean preprocess(String[] anArgs) {
// run the preprocessor to handle inheritance first.
com.javadude.antxr.preprocessor.Tool preTool = new com.javadude.antxr.preprocessor.Tool(this,
anArgs);
if (preTool.preprocess()) {
fPreprocessedArgs = preTool.preprocessedArgList();
} else {
fPreprocessedArgs = null;
hasError = true;
}
return hasError;
}
/**
* Parse the grammar file.
* Can only be called after calling preprocess().
* @return true if there was an error; false otherwise
* @throws CoreException If eclipse got upset
*/
public boolean parse() throws CoreException {
if (fPreprocessedArgs == null) {
throw createException("AntxrTool.error.missingPreprocess");
}
// process arguments for the Tool
processArguments(fPreprocessedArgs);
if (!hasError) {
Reader reader = getGrammarReader();
ANTXRLexer lexer = new ANTXRLexer(reader);
fAnalyzer = new LLkAnalyzer(this);
fBehavior = new MakeGrammar(this, fPreprocessedArgs, fAnalyzer);
fParser = new ANTXRParser(new TokenBuffer(lexer), fBehavior, this);
fParser.setFilename(grammarFile);
try {
fParser.grammar();
} catch (IllegalStateException e) {
// Thrown by AntxrTool.fatalError()
System.err.println(e.toString());
hasError = true;
} catch (RecognitionException e) {
System.err.println(
FileLineFormatter.getFormatter().getFormatString(
null, e.getLine(), e.getColumn())
+ e.getMessage());
hasError = true;
} catch (TokenStreamException e) {
if (e instanceof TokenStreamRecognitionException) {
System.err.println(e.toString());
} else if (e.getMessage() != null) {
System.err.println(
FileLineFormatter.getFormatter().getFormatString(
null, -1, -1)
+ e.getMessage());
}
hasError = true;
} finally {
// Close all writers opened during grammar inheritance
// (expanded grammar files)
Iterator writers = fWriters.iterator();
while (writers.hasNext()) {
PrintWriter writer = (PrintWriter)writers.next();
writer.close();
}
// Close reader
try {
reader.close();
} catch (IOException e) {
throw createException("AntxrTool.error.canNotCloseFile",
grammarFile, e);
}
}
}
return hasError;
}
/**
* Run the code generation
* @return true if there was an error; false otherwise
* @throws CoreException If eclipse got upset
*/
public boolean generate() throws CoreException {
if (fParser == null) {
throw createException("AntxrTool.error.missingParse");
} else if (!hasError) {
fFiles.clear();
fWriters.clear();
// Create the right code generator according to the
// "language" option
String codeGenClassName = "com.javadude.antxr." + getLanguage(fBehavior) +
"CodeGenerator";
try {
CodeGenerator codeGen = (CodeGenerator)
Class.forName(codeGenClassName).newInstance();
codeGen.setBehavior(fBehavior);
codeGen.setAnalyzer(fAnalyzer);
codeGen.setTool(this);
codeGen.gen();
if (codeGen instanceof JavaCodeGenerator) {
sourceMaps = ((JavaCodeGenerator) codeGen).getPrintWriterManager().getSourceMaps();
}
} catch (ClassNotFoundException e) {
throw createException("AntxrTool.error.noCodeGenerator",
codeGenClassName, e);
} catch (InstantiationException e) {
throw createException("AntxrTool.error.noCodeGenerator",
codeGenClassName, e);
} catch (IllegalArgumentException e) {
throw createException("AntxrTool.error.noCodeGenerator",
codeGenClassName, e);
} catch (IllegalAccessException e) {
throw createException("AntxrTool.error.noCodeGenerator",
codeGenClassName, e);
} catch (IllegalStateException e) {
// Thrown in fatalError() - ignore
hasError = true;
} finally {
// Close all writers opened during code generation
Iterator writers = fWriters.iterator();
while (writers.hasNext()) {
PrintWriter writer = (PrintWriter)writers.next();
writer.close();
}
}
}
return hasError;
}
private CoreException createException(String aKey) {
return createException(aKey, (String[])null, null);
}
private CoreException createException(String aKey, String anArg,
Throwable aThrowable) {
return createException(aKey, new String[] { anArg }, aThrowable);
}
private CoreException createException(String aKey, String[] anArgs,
Throwable aThrowable) {
String msg = (anArgs == null ? AntxrCorePlugin.getMessage(aKey) :
AntxrCorePlugin.getFormattedMessage(aKey, anArgs));
return new CoreException(new Status(IStatus.ERROR,
AntxrCorePlugin.PLUGIN_ID, IStatus.OK, msg, aThrowable));
}
private class MarkerFormatter extends FileLineFormatter {
/**
* Returns given information separated by a '|'.
*
* @param aFileName the file that should appear in the prefix (or null)
* @param aLine the line (or -1)
* @param aColumn the column (or -1)
* @see com.javadude.antxr.FileLineFormatter#getFormatString(java.lang.String, int, int)
*/
public String getFormatString(String aFileName, int aLine,
int aColumn) {
StringBuffer buf = new StringBuffer();
if (aFileName != null) {
buf.append(aFileName);
} else {
buf.append("<noname>");
}
buf.append('|').append(aLine).append('|').append(aColumn).
append('|');
return buf.toString();
}
}
/**
* @return source maps
*/
public Map getSourceMaps() {
return sourceMaps;
}
}