/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.backend.prolog;
import java.io.*;
import java.util.*;
import java.util.List;
import abs.common.NotImplementedYetException;
import abs.frontend.ast.*;
import abs.frontend.parser.Main;
public class PrologBackend extends Main {
private File destDir = new File(".");
protected File outFile;
protected PrintStream outStream;
private String outFilename = "abs.pl";
private Model model;
private ReachabilityInformation reachInfo = null;
ArrayList<ASTNode<?>> entries = null;
public static int awaitId = 0;
public static boolean entriesMode = false;
public static void main(final String... args) {
runFromShell(args);
}
public static void runFromShell(final String[] args){
awaitId = 0;
PrologBackend prologBE = null;
try {
prologBE = new PrologBackend(args);
prologBE.generateProlog();
if (Arrays.asList(args).contains("-v"))
System.out.println("ABS file parsed to Prolog terms in " + prologBE.outFile.getAbsolutePath());
} catch (NotImplementedYetException e) {
System.err.println(e.getMessage());
} catch (Exception e) {
if (Arrays.asList(args).contains("-v")) {
System.err.println("An error occurred during compilation:\n" + e.getMessage());
e.printStackTrace();
}
//System.exit(1);
} finally {
if (prologBE != null && prologBE.outStream != null) prologBE.outStream.close();
}
}
public static void runFromPlugin(Model m,String dir,String fn,ArrayList<ASTNode<?>> entries){
awaitId = 0;
PrologBackend prologBE = null;
try {
prologBE = new PrologBackend(m,dir,fn,entries);
prologBE.generateProlog();
} catch (Exception e) {
System.err.println("Error in Prolog backend: " + e.getMessage());
} finally {
if (prologBE != null && prologBE.outStream != null) prologBE.outStream.close();
}
}
// This is the constructor used from runFromShell
public PrologBackend(String[] args) throws Exception {
// This parses the args and the ABS program producing the AST whose root is model
model = parse(args);
if (model.hasParserErrors() || model.hasErrors() || model.hasTypeErrors())
printParserErrorAndExit();
initOutStreamEtc();
}
// This is the constructor used from runFromPlugin
public PrologBackend(Model m,String dir,String fn,ArrayList<ASTNode<?>> es) throws Exception {
model = m;
destDir = new File(dir);
entries = es;
initOutStreamEtc();
}
private void initOutStreamEtc() throws Exception {
destDir.mkdirs();
if (!destDir.exists()) {
System.err.println("Destination directory " + destDir.getAbsolutePath() + " does not exist!");
System.exit(1);
}
if (!destDir.canWrite()) {
System.err.println("Destination directory " + destDir.getAbsolutePath() + " cannot be written to!");
System.exit(1);
}
if (verbose)
printAST(model, 0);
outFile = new File(destDir, outFilename);
// destDir and outFilename are initialized either in the constructor or in parseArgs,
// which is called from parse
outStream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outFile)));
}
private void generateProlog(){
if (entries != null){ // mode with entries
entriesMode = true;
collectReachableCode(entries);
}
//print discontiguous predicate to avoid warnings when loading the file
outStream.print(":-discontiguous mainBlock/3,def/6, data/3,methodImpl/5,"+
"module/1, starImport/1,type/2,interface/3,class/3.\n");
model.generateProlog(outStream,reachInfo);
}
private void collectReachableCode(ArrayList<ASTNode<?>> entries) {
reachInfo = new ReachabilityInformation(entries);
while (reachInfo.changed()) {
try {
model.collectReachableCode(reachInfo);
} catch (Exception e){
e.printStackTrace();
}
}
//System.out.println(reachInfo.toString());
}
public List<String> parseArgs(String[] args) {
List<String> restArgs = super.parseArgs(args);
List<String> remainingArgs = new ArrayList<String>();
for (int i = 0; i < restArgs.size(); i++) {
String arg = restArgs.get(i);
if (arg.equals("-prolog")) {
// nothing to do
} else if (arg.equals("-d")) {
i++;
if (i == restArgs.size()) {
System.err.println("Please provide a destination directory");
System.exit(1);
} else {
destDir = new File(args[i]);
}
} else if (arg.equals("-fn")) {
i++;
if (i == restArgs.size()) {
System.err.println("Please provide a file name");
System.exit(1);
} else {
outFilename = args[i];
}
} else {
remainingArgs.add(arg);
}
}
return remainingArgs;
}
protected void printUsage() {
super.printUsage();
System.out.println("Prolog Backend:");
System.out.println(" -d <dir> generate files to <dir>");
System.out.println(" -fn <dir> output file name");
}
private void printAST(ASTNode<?> ast, int level) {
if (ast != null) {
printTab(level);
System.out.println(level + ":" + ast.getClass().getName() + "@" + ast.getId());
int n = ast.getNumChild();
for (int i = 0; i < n; i++)
printAST(ast.getChild(i), level + 1);
}
}
private void printTab(int n) {
for (int i = 0; i < n; i++)
System.out.print(" ");
}
// Auxiliary methods
public static String initialToUpperCase(String s){
char[] cs = s.toCharArray();
cs[0] = Character.toUpperCase(cs[0]);
return new String(cs);
}
public static String varTransform(String s){
return "l('"+s+"')";
}
public static String fieldTransform(String s){
return "field('"+s+"')";
}
public static String strTransform(String s){
return "str('"+s+"')";
}
public static String quote(String s){
return "'" + s + "'";
}
}