/*
* xtc - The eXTensible Compiler
* Copyright (C) 2011 Robert Grimm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.oop;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.util.LinkedList;
import xtc.parser.ParseException;
import xtc.parser.Result;
import xtc.tree.GNode;
import xtc.tree.Node;
import xtc.tree.Visitor;
import xtc.lang.JavaFiveParser;
/**
* A translator from (a subset of) Java to (a subset of) C++.
*
* @author Robert Grimm
* @version $Revision$
*/
public class TestTranslator extends xtc.util.Tool {
private String outFileName = "";
/** Create a new translator. */
public TestTranslator() {
// Nothing to do.
}
public String getName() {
return "JavaGrinder - A Java to C++ Translator";
}
public String getCopy() {
return "Christopher Lee, Daniel Uebelein, Justin Bernegger, & Steven Socha";
}
public void init() {
super.init();
runtime.
bool("printJavaAST", "printJavaAST", false, "Print Java AST.").
bool("countMethods", "countMethods", false, "Count all Java methods.").
bool("translate", "translate", false, "Translate a Java file to a C++ file.");
}
public Node parse(Reader in, File file) throws IOException, ParseException {
outFileName = file.getName().substring(0, file.getName().indexOf('.')); // This is the only place I could find where I could save the name of the argument file.
JavaFiveParser parser = // But I'm ignorant and there's probably a more elegant way of getting it.
new JavaFiveParser(in, file.toString(), (int)file.length());
Result result = parser.pCompilationUnit(0);
return (Node)parser.value(result);
}
/*
* Existing Issues
* - Not all visitors created so the printing of each line (cc or h) will not be perfect at all, predict outputs using AST before testing
* - Formatting will be a constant issue as we add in more visitors, debug and check outputs often
* - primitive types are not c++ 32bit versions (ex int32_t), have to change that
* - most of the formatting to c++ has not been done yet
*/
public void process(Node node) {
if (runtime.test("printJavaAST")) {
runtime.console().format(node).pln().flush();
}
if (runtime.test("translate")) {
new Visitor() {
private FileWriter writerCC;
private FileWriter writerH;
private File fileCC;
private File fileH;
private BufferedWriter outCC;
private BufferedWriter outH;
private LinkedList<String> includesCC;
private LinkedList<String> nameSpaceCC;
private LinkedList<String> methodCC;
private LinkedList<String> vTableDefCC;
private LinkedList<String> includesH;
private LinkedList<String> nameSpaceH;
private LinkedList<String> forwardDeclarationsH;
private LinkedList<String> constructorH;
private LinkedList<String> dataLayoutH;
private LinkedList<String> methodsImplementedH;
private LinkedList<String> vTableH;
private LinkedList<String> vTableLayoutH;
private String[] ccstring;
private String[] hstring;
private boolean hflag;
//the source directory for the .java files
private String basedirectory = "./";
/** What it says on the tin.*/
private void createFilesAndWriters(){
try{
fileCC = new File(basedirectory + outFileName + ".cc");
fileH = new File(basedirectory + outFileName + ".h");
fileCC.createNewFile();
fileH.createNewFile();
includesCC = new LinkedList<String>();
includesCC.add("#include \""+outFileName+".h\"");
nameSpaceCC = new LinkedList<String>();
methodCC = new LinkedList<String>();
vTableDefCC = new LinkedList<String>();
includesH = new LinkedList<String>();
nameSpaceH = new LinkedList<String>();
forwardDeclarationsH = new LinkedList<String>();
constructorH = new LinkedList<String>();
dataLayoutH = new LinkedList<String>();
methodsImplementedH = new LinkedList<String>();
vTableH = new LinkedList<String>();
vTableLayoutH = new LinkedList<String>();
writerCC = new FileWriter(fileCC);
writerH = new FileWriter(fileH);
outCC = new BufferedWriter(writerCC);
outH = new BufferedWriter(writerH);
ccstring = new String[8];
hstring = new String[8];
//we want to create a blank string that will not print null
for(int j = 0; j < 8;j++){
hstring[j] = " ";
hstring[j] = hstring[0].replace(" ", "");
ccstring[j] = " ";
ccstring[j] = ccstring[0].replace(" ", "");
}
}
catch (IOException e){
e.printStackTrace();
System.out.println("Something's up with the files and writers. Bitch.");
}
}
/** Final aseembly of .cc and .h files */
private void assembleFile(){
assembleElement(includesCC,outCC);
assembleElement(nameSpaceCC,outCC);
assembleElement(methodCC,outCC);
assembleElement(vTableDefCC,outCC);
try {
outCC.close();
} catch (IOException e) {
e.printStackTrace();
}
assembleElement(includesH,outH);
assembleElement(nameSpaceH,outH);
assembleElement(forwardDeclarationsH,outH);
assembleElement(constructorH,outH);
assembleElement(dataLayoutH,outH);
assembleElement(methodsImplementedH,outH);
assembleElement(vTableH,outH);
assembleElement(vTableLayoutH,outH);
try {
outH.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Aseembles elements from list into appropriate file.
*
* @param Element List of elements.
* @param file File aseembled to (outH or outCC).
*/
private void assembleElement(LinkedList<String> Element, BufferedWriter file){
while(!Element.isEmpty()){
try {
file.write((String)Element.remove(0)+"\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Visiting the Compilation Unit, which is parent of everything.
*
* @param n It's the Node, genius.
*/
public void visitCompilationUnit(GNode n){
createFilesAndWriters();
visit(n);
assembleFile();
}
//covers byte, int, short, long
public void visitIntegerLiteral(GNode n){
if(hflag == true){
hstring[0] = hstring[0] + n.getString(0);
}
else{
ccstring[0] = ccstring[0] + n.getString(0);
}
//System.out.print(n.getString(0));
}
public void visitBooleanLiteral(GNode n){
if(hflag == true){
hstring[0] = hstring[0] + n.getString(0);
}
else{
ccstring[0] = ccstring[0] + n.getString(0);
}
//System.out.print(n.getString(0));
}
//covers doubles and floats
public void visitFloatingPointLiteral(GNode n){
//System.out.println("Double Literal Test: " + n.getString(0));
if(hflag == true){
hstring[0] = hstring[0] + n.getString(0);
}
else{
ccstring[0] = ccstring[0] + n.getString(0);
}
//System.out.print(n.getString(0));
}
public void visitStringLiteral(GNode n){
//System.out.println("String Literal Test: " + n.getString(0));
if(hflag == true){
hstring[0] = hstring[0] + n.getString(0);
}
else{
ccstring[0] = ccstring[0] + n.getString(0);
}
//System.out.print(n.getString(0));
}
//handles addition and subtraction
public void visitAdditiveExpression(GNode n){
ExpressionHandler(n);
//System.out.print("\n");
}
//handles multiplication, division and modulus
public void visitMultiplicativeExpression(GNode n){
ExpressionHandler(n);
}
//Single Expression Statement
public void visitExpressionStatement(GNode n){
visit(n);
if (hflag == true){
hstring[0] = hstring[0] + ";\r";
}
else{
ccstring[0] = ccstring[0] + ";\r";
}
//System.out.print(";\r");
}
//Standard Expression
public void visitExpression(GNode n){
ExpressionHandler(n);
}
//Primary Handler for all Expression nodes
public void ExpressionHandler(GNode n){
for(Object o: n){
if (o instanceof Node){
dispatch((Node)o);
}
else{
if(o != null){
if (hflag == true){
hstring[0] = hstring[0] + ((String)o).toString();
}
else{
ccstring[0] = ccstring[0] + ((String)o).toString();
}
}
//System.out.print(((String)o).toString());
}
}
}
public void visitFieldDeclaration(GNode n){
visit(n);
}
public void visitType(GNode n){
visit(n);
}
//primitive type specific, ex int, double, float, etc.
public void visitPrimitiveType(GNode n){
if (hflag == true){ //this type belongs to the .h file
hstring[0] = hstring[0] + n.getString(0) + " ";
}
else{ //this type belongs to the .cc file
ccstring[0] = ccstring[0] + n.getString(0) + " ";
}
//System.out.println(n.getString(0));
}
//the name of the variable
public void visitPrimaryIdentifier(GNode n){
if (hflag == true){ //this type belongs to the .h file
hstring[0] = hstring[0] + n.getString(0);
}
else{ //this type belongs to the .cc file
ccstring[0] = ccstring[0] + n.getString(0);
}
//System.out.print(n.getString(0));
}
//object type, ex String -- note, not actually complete, needs c++ translation
public void visitQualifiedIdentifier(GNode n){
hflag = true;
int j = 0;
while(n.size()>j){
if (hflag == true){ //this type belongs to the .h file
hstring[j] = hstring[j] + n.getString(j) + " ";
}
else{ //this type belongs to the .cc file
ccstring[j] = ccstring[j] + n.getString(j);
}
j++;
}
}
//container for Modifier nodes
public void visitModifiers(GNode n){
visit(n);
}
//public, private, protected, abstract, static, etc.
public void visitModifier(GNode n){
//System.out.println("Modifier Test: " + n.getString(0) + " ");
if (hflag == true){ //this type belongs to the .h file
hstring[0] = hstring[0] + n.getString(0) + " ";
}
else{ //this type belongs to the .cc file
ccstring[0] = ccstring[0] + n.getString(0) + " ";
}
//System.out.print(n.getString(0) + " ");
}
//container for Declarator nodes
public void visitDeclarators(GNode n){
visit(n);
}
//Large construct for declaring a variable
public void visitDeclarator(GNode n){
if(hflag == true){
hstring[0] = hstring[0] + n.getString(0); //check for other children, if has children then =, else nothing
System.out.println(n.hasVariable());
if(n.hasVariable())
hstring[0]+="=";
visit(n);
hstring[0] = hstring[0] + "; \r";
methodCC.add(ccstring[0]);
}
else{
ccstring[0] = ccstring[0] + n.getString(0) + "=";
visit(n);
ccstring[0] = ccstring[0] + "; \r";
methodCC.add(ccstring[0]);
}
//System.out.print(n.getString(0));
//if(n.get(1) != null) visit(n.getNode(1));
//System.out.print("=");
//visit(n);
//System.out.print(";\r");
}
public void visitBlock(GNode n){
visit(n);
}
//large construct for the body of a Class
public void visitClassBody(GNode n){
for(Object o: n){
if (o instanceof Node){
if(((GNode)o).getName().equals("FieldDeclaration")){
hflag = true;
//System.out.println("Translation Note: hfile access");
}
else{
hflag = false;
}
dispatch((Node)o);
//we want to create a blank string that will not print null
if(hflag == true){
System.out.println(hstring[0]);
includesCC.add(hstring[0]);
hstring[0] = " ";
hstring[0] = hstring[0].replace(" ", "");
}
else{
System.out.println(ccstring[0]);
ccstring[0] = " ";
ccstring[0] = ccstring[0].replace(" ", "");
}
}
else{
//if(o != null)
//System.out.print(((String)o).toString());
}
}
}
public void visitConstructorDeclaration(GNode n){
visit(n);
}
//method arguments
public void visitFormalParameters(GNode n){
//add the first parenthesis
visit(n);
//add the closing parenthesis and the opening curly brace
}
public void visitFormalParameter(GNode n){
for(Object o: n){
if (o instanceof Node){
dispatch((Node)o);
}
else{
if(o != null){
if (hflag == true){
hstring[0] = hstring[0] + ((String)o).toString();
}
else{
ccstring[0] = ccstring[0] + ((String)o).toString();
}
}
//System.out.print(((String)o).toString());
}
}
}
public void visitImportDeclaration(GNode n){ //ToDo: Separate .cc and .h imports
ccstring[0]+="#include <";
for(Object o: n){
if (o instanceof Node){
dispatch((Node)o);
}
else{
if(o != null){
if (hflag == true){
hstring[0] = hstring[0] + ((String)o).toString();
}
else{
ccstring[0] = ccstring[0] + ((String)o).toString();
}
}
}
}
ccstring[0] += ">;";
includesCC.add(ccstring[0]);
ccstring[0]="";
}
public void visitPackageDeclaration(GNode n){
hflag = true;
visit(n);
for(int k=0;k<hstring.length;k++)
if(hstring[k]!=" ")
System.out.println(hstring[k]);
hflag = false;
}
/**
* Visiting a Class Declaration.
*
* @param n It's the Node, smarty.
*/
public void visitClassDeclaration(GNode n){
// String sprfilename = new String(basedirectory + outFileName + ".cc");
// File argstest = new File(sprfilename);
//
//
// System.out.println(fileCC.getPath());
visit(n);
// if(!argstest.exists()){
// System.out.println("We are in here!");
// String[] args = new String[2];
// args[0] = ("-translate");
// args[1] = (basedirectory + outFileName + ".java");
// TestTranslator trans = new TestTranslator();
// trans.run(args);
// }
}
/** visiting... anything else? */
public void visit(Node n) {
//methodCC.add("Dadsa");
for (Object o : n) if (o instanceof Node) dispatch((Node)o);
}
}.dispatch(node);
}
}
/**
* Run the translator with the specified command line arguments.
*
* @param args The command line arguments.
*/
public static void main(String[] args) {
new TestTranslator().run(args);
}
}