package de.dhbwstuttgart.core; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import de.dhbwstuttgart.typeinference.Menge; import de.dhbwstuttgart.logger.Logger; import de.dhbwstuttgart.logger.LoggerConfiguration; import de.dhbwstuttgart.logger.Section; import de.dhbwstuttgart.parser.JavaParser; import de.dhbwstuttgart.parser.Scanner; import de.dhbwstuttgart.parser.JavaParser.yyException; import de.dhbwstuttgart.syntaxtree.Class; import de.dhbwstuttgart.syntaxtree.ClassBody; import de.dhbwstuttgart.syntaxtree.FormalParameter; import de.dhbwstuttgart.syntaxtree.ImportDeclarations; import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.ParameterList; import de.dhbwstuttgart.syntaxtree.SourceFile; import de.dhbwstuttgart.syntaxtree.misc.DeclId; import de.dhbwstuttgart.syntaxtree.misc.UsedId; import de.dhbwstuttgart.syntaxtree.type.GenericTypeVar; import de.dhbwstuttgart.syntaxtree.type.IMatchable; import de.dhbwstuttgart.syntaxtree.type.ITypeContainer; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.Type; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.typeinference.ByteCodeResult; import de.dhbwstuttgart.typeinference.FunNInterface; import de.dhbwstuttgart.typeinference.FunVoidNInterface; import de.dhbwstuttgart.typeinference.Pair; import de.dhbwstuttgart.typeinference.ResultSet; import de.dhbwstuttgart.typeinference.TypeinferenceResultSet; import de.dhbwstuttgart.typeinference.TypeinferenceResults; import de.dhbwstuttgart.typeinference.assumptions.TypeAssumptions; import de.dhbwstuttgart.typeinference.exceptions.DebugException; import de.dhbwstuttgart.typeinference.exceptions.ParserError; import de.dhbwstuttgart.typeinference.exceptions.TypeinferenceException; public class MyCompiler implements MyCompilerAPI{ // PL: Der Zusammenhang zwischen paralist und vParaOrg muesste // noch geklaert werden 05-01-07 public static final int NO_LINENUMBER = -1; protected static Logger inferencelog = Logger.getLogger(MyCompiler.class.getName()); protected String OutputDir = ""; public Menge<Pair> testPair = null; /** * Author: J�rg B�uerle<br/> * Der private Konstruktor. Es soll von au�en kein Compiler angelegt werden * k�nnen, sondern nur eine API zur Verf�gung gestellt werden. * @param logger Konfiguration für Debug Ausgabe TODO */ private MyCompiler(){ this.init(); } /** * Author: Jörg Bäuerle<br/> * Stellt eine neue Instanz der CompilerAPI zur Verf�gung. * Diese Methode sollte von der IDE aus aufgerufen werden, * um eine Quellcode-Datei zu kompilieren. * @return Die Compiler-API */ public static MyCompilerAPI getAPI(LoggerConfiguration loggerConfig){ Logger.setStandardConfiguration(loggerConfig); return new MyCompiler(); } /** * Parst den Quellcode und baut den abstrakten Syntaxbaum auf. Danach wird * automatisch der von Thomas Ott implementierte Algorithmus * <code>NewTVar(jclass)</code> (siehe Algorithmus 5.17 TRProg, Martin Pl�micke) * aufgerufen. * <br/>Author: J�rg B�uerle * @param reader * @throws IOException * @throws JavaParser.yyException */ private void parse_backup(Reader reader) throws IOException, JavaParser.yyException{ } ///////////////////////////////////////////////////////////////////////////////////////////////// // Implementierte API-Methoden: ///////////////////////////////////////////////////////////////////////////////////////////////// /** * Author: J�rg B�uerle<br/> * Initialisiert den Compiler */ public void init(){ TypePlaceholder.deleteRegistry(); } /** * Author: J�rg B�uerle<br/> * Ruft die Parse-Methode. * @param file Die Quellcode-Datei * @throws FileNotFoundException Wenn die Quellcode-Datei nicht existiert. * @throws IOException Wenn was schief l�uft. * @throws JavaParser.yyException Wenn ein Fehler beim Parsen auftritt. */ public SourceFile parse(File file) throws FileNotFoundException, IOException, JavaParser.yyException{ FileReader fr = new FileReader(file); SourceFile ret = this.parse2SyntaxTree(fr); fr.close(); return ret; } /** * Author: J�rg B�uerle<br/> * Ruft den Typrekonstruktionsalgorithmus auf. * @return Die Menge aller m�glichen Typkombinationen * @throws NullPointerException Wenn noch kein abstrakter Syntaxbaum vorhanden * ist. @throws CTypeReconstructionException Wenn ein Fehler bei der * Typrekonstruktion auftritt. */ public Menge<TypeinferenceResultSet> typeReconstruction(Menge<SourceFile> m_AbstractSyntaxTree) throws NullPointerException{ inferencelog.info("##########################################", Section.TYPEINFERENCE); inferencelog.info("# TypeReconstruction-Algorithmus - START #", Section.TYPEINFERENCE); inferencelog.info("##########################################\n", Section.TYPEINFERENCE); TypeAssumptions globalAssumptions = makeFunNAssumptions(); Menge<TypeinferenceResultSet> result = new Menge<TypeinferenceResultSet>(); for(SourceFile srcFile : m_AbstractSyntaxTree){ result.addAll(srcFile.typeReconstruction(globalAssumptions)); } inferencelog.info("#########################################", Section.TYPEINFERENCE); inferencelog.info("# TypeReconstruction-Algorithmus - ENDE #", Section.TYPEINFERENCE); inferencelog.info("#########################################\n", Section.TYPEINFERENCE); return result; } /** * Erstellt die FunN-Assumptions * Fun0-FunN (momentan für N = 6) * @return */ public static TypeAssumptions makeFunNAssumptions(){ TypeAssumptions ret = new TypeAssumptions(); //Basic Assumptions für die FunN Interfaces: //TODO: Hier mehr als Fun1-Fun5 implementieren for(int i = 0; i<6; i++){ FunNInterface funN = new FunNInterface(i); ret.add(funN.getPublicFieldAssumptions()); } for(int i = 0; i<6; i++){ FunVoidNInterface funN = new FunVoidNInterface(i); ret.add(funN.getPublicFieldAssumptions()); } return ret; } /** * Die Main-Funktion, �ber die der Compiler auch per Konsole gestartet * werden kann. * @param args Klassendatei */ public static void main(String[] args){ MyCompilerAPI compiler = MyCompiler.getAPI(new LoggerConfiguration()); // Hier koennten ggf. Aenderungen der Ausgabeeinstellungen // (Debuginfos) vorgenommen werden -> LOG4J try { compiler.parse(new File(args[0])); } catch (FileNotFoundException e) { System.err.println("Die Datei \""+args[0]+"\" konnte nicht gefunden werden."); System.exit(0); } catch (IOException e) { System.err.println("Fehler beim Parsen:"); System.err.println(e); System.exit(0); } catch (yyException e) { System.err.println("Fehler beim Parsen:"); System.err.println(e); System.exit(0); } } public void setOutputDir(String dir){ char c = dir.charAt(dir.length()-1); if (c != '/' & c != '\\') dir = dir + "/"; OutputDir = dir; // Verzeichnis(se) ggf. anlegen File f = new File(dir); f.mkdirs(); } public String getOutputDir(){ return OutputDir; } /** * Parst den Inhalt einer Datei zu einem Syntaxbaum. */ private SourceFile parse2SyntaxTree(Reader fileContent) throws ParserError{ //StringReader reader = new StringReader(fileContent); ////////////////////////////////////// // Scanner und Parser erzeugen: ////////////////////////////////////// Scanner scanner = new Scanner(fileContent); JavaParser parser = new JavaParser(); ////////////////////////////////////// // Parsen ==> Ergebnis: srcFile ////////////////////////////////////// SourceFile srcFile = null; try { srcFile = (SourceFile) parser.yyparse( scanner ); } catch (IOException | yyException e) { e.printStackTrace(); if(e instanceof yyException)throw new ParserError((yyException)e); } ////////////////////////////////////// // Postprocessing: ////////////////////////////////////// srcFile.parserPostProcessing(null); //Muss mit null aufgerufen werden. //Fertig: return srcFile; } /** * Diese Funktion nimmt einen Menge von Dateinamen. Alle diese Dateien werden zu einem SyntaxBaum geparst. * @return */ public Menge<SourceFile> parse(Menge<String> filenames) throws ParserError { Menge<SourceFile> m_AbstractSyntaxTree = new Menge<SourceFile>(); for(String filename : filenames){ StringBuffer fileData = new StringBuffer(); BufferedReader reader; try { reader = new BufferedReader( new FileReader(filename)); } catch (FileNotFoundException e) { throw new DebugException("Die Datei "+ filename+" konnte nicht gelesen werden."); } char[] buf = new char[1024]; int numRead=0; try { while((numRead=reader.read(buf)) != -1){ String readData = String.valueOf(buf, 0, numRead); fileData.append(readData); } reader.close(); } catch (IOException e) { e.printStackTrace(); } StringReader srcreader = new StringReader(fileData.toString()); //Den aus der Datei ausgelesenen Quellcode zu einem Syntaxbaum parsen: m_AbstractSyntaxTree.add(parse2SyntaxTree(srcreader)); // Alle Dateien nacheinander hintereinander anhängen... } return m_AbstractSyntaxTree; } @Override public SourceFile parse(String sourceCode) { return parse2SyntaxTree(new StringReader(sourceCode)); } @Override public Menge<ByteCodeResult> generateBytecode(Menge<SourceFile> m_AbstractSyntaxTree, TypeinferenceResults typeinferenceResults) { //SourceFile parsedFile = this.m_AbstractSyntaxTree.firstElement(); //Class parsedClass = parsedFile.KlassenVektor.firstElement(); Menge<ByteCodeResult> ret = new Menge<>(); for(SourceFile sf : m_AbstractSyntaxTree){ ret.addAll(sf.generateBytecode(typeinferenceResults)); } return ret; } }