Example #1
0
    public ICompilerOutput<Project> CompileProject(Project project, StandardOutputCallback standardOutput)
    {
        #region split up every file in the project into a code file

        fileObj[] assemblyFiles = new fileObj[0];
        fileObj[] cCodeFiles = new fileObj[0];
        fileObj[] cHeaderFiles = new fileObj[0];

        project.Root.Enumerate(true, delegate(ProjectEntity e) {
            if (!(e is ProjectFile)) { return true; }

            //add the filename into the appropriate code file list
            ProjectFile file = (ProjectFile)e;
            string ext = file.Extension.ToLower();
            switch (ext) {
                case ".c":
                    Helpers.AddObject(ref cCodeFiles, new fileObj(file));
                    break;
                case ".h":
                    Helpers.AddObject(ref cHeaderFiles, new fileObj(file));
                    break;
                case ".asm":
                    Helpers.AddObject(ref assemblyFiles, new fileObj(file));
                    break;
            }
            return true;
        });
        #endregion

        //define the final output file
        string finalOutput = getOuputFilename(project, "build.bin");
        StandardCompileOutput<Project> output = new StandardCompileOutput<Project>(finalOutput, project);
        string[] outputFiles = new string[0];
        if (File.Exists(finalOutput)) { File.Delete(finalOutput); }

        //define whether or not the assembly code should
        //be linked (no point in linking if theres nothing
        //to link with)
        bool linkable = cCodeFiles.Length != 0 || cHeaderFiles.Length != 0;

        //compile the assembly
        if (assemblyFiles.Length != 0) {
            //make sure that the main entry point assembly file is at the top
            //of the list to be compiled first.
            int bootfileIndex = -1;
            for (int c = 0; c < assemblyFiles.Length; c++) {
                if (assemblyFiles[c].ProjectFile.Name.ToLower() == "boot.asm") {
                    bootfileIndex = c;
                    break;
                }
            }
            if (bootfileIndex != -1) {
                Helpers.SwapEntries(ref assemblyFiles, bootfileIndex, 0);
            }

            string asmOut = getOuputFilename(project, "asm.o");
            compileAssembly(linkable, asmOut, output, assemblyFiles, standardOutput);
            Helpers.AddObject(ref outputFiles, asmOut);

            //if there are no C code/header files, then there is no point
            //compiling and linking them with the ASM code.
            if (!linkable) {
                if (File.Exists(asmOut)) {
                    File.Move(asmOut, finalOutput);
                }
                return output;
            }
        }

        //compile all the C code
        string cOut = getOuputFilename(project, "c.o");
        compileC(cOut, output, cCodeFiles, cHeaderFiles, standardOutput);
        Helpers.AddObject(ref outputFiles, cOut);

        //if there was no success, do not continue with linking.
        if (output.Errors.Length != 0) { return output; }

        //link the c and assembly code together.
        link(
            outputFiles,
            finalOutput,
            output,
            standardOutput);
        return output;
    }
Example #2
0
    private void resolveFile(outputEntry outputEntry, fileObj[] files, out ProjectFile file, out int line)
    {
        long lineTotal = 0;
        file = null;
        line = -1;
        for (int c = 0; c < files.Length; c++) {
            fileObj entry = files[c];

            int relativeLine = (int)(outputEntry.line - lineTotal);
            if (relativeLine <= entry.LineLength) {
                line = relativeLine;
                file = entry.ProjectFile;
                return;
            }
            lineTotal += entry.LineLength;
        }
    }
Example #3
0
 private void processCompileResults(fileObj[] files, StandardCompileOutput<Project> output, outputEntry[] errors, outputEntry[] warnings)
 {
     for (int c = 0; c < errors.Length; c++) {
         ProjectFile file;
         int line;
         resolveFile(errors[c], files, out file, out line);
         output.addError(
             file,
             line,
             errors[c].column,
             errors[c].message);
     }
     for (int c = 0; c < warnings.Length; c++) {
         ProjectFile file;
         int line;
         resolveFile(warnings[c], files, out file, out line);
         output.addWarning(
             file,
             line,
             warnings[c].column,
             warnings[c].message);
     }
 }
Example #4
0
    private void compileC(string outputFile, StandardCompileOutput<Project> output, fileObj[] codeFiles, fileObj[] headerFiles, StandardOutputCallback stdOut)
    {
        if (File.Exists(outputFile)) { File.Delete(outputFile); }

        //collapse the code files and header files into one array but add the header files first.
        fileObj[] files = new fileObj[0];
        Helpers.AddObject(ref files, headerFiles);
        Helpers.AddObject(ref files, codeFiles);

        //flatten the files down to a single file
        string collapsed = collapseFiles(files, ".c");

        //perform the compile
        outputEntry[] errors = new outputEntry[0];
        outputEntry[] warnings = new outputEntry[0];
        compileC(ref errors, ref warnings, collapsed, outputFile, stdOut);
        processCompileResults(codeFiles, output, errors, warnings);

        //clean up
        File.Delete(collapsed);
    }
Example #5
0
    private void compileAssembly(bool linkable, string outputFile, StandardCompileOutput<Project> output, fileObj[] files, StandardOutputCallback stdOut)
    {
        if (File.Exists(outputFile)) { File.Delete(outputFile); }

        //collapse all the files into one file to compile
        string collapsed = collapseFiles(files, ".asm");

        //compile
        outputEntry[] errors = new outputEntry[0];
        outputEntry[] warnings = new outputEntry[0];
        compileAssembly(linkable, ref errors, ref warnings, collapsed, outputFile, stdOut);
        processCompileResults(files, output, errors, warnings);

        //clean up
        File.Delete(collapsed);
    }
Example #6
0
    private string collapseFiles(fileObj[] files, string extension)
    {
        //create the file to collapse all the files into
        string filename;
        Stream stream = Helpers.CreateTempFile(extension, out filename);

        //read and then write every file in the file array
        //to the temporary file
        for (int c = 0; c < files.Length; c++) {
            //read the file data
            FileStream readStream = new FileStream(files[c].Filename, FileMode.Open);
            byte[] fileData = new byte[readStream.Length];
            readStream.Read(fileData, 0, fileData.Length);

            //is there a newline character at the end of data?
            //if not, we need to write it. Otherwise we get
            //a mismatch when getting a file from an absolute line position
            //later on when we get the origination of errors/warnings.
            bool hasNewLineCharEnding = false;
            if (fileData.Length >= 2) {
                int len = fileData.Length;
                if (fileData[len - 2] == '\n' || fileData[len - 1] == '\n') {
                    hasNewLineCharEnding = true;
                }
            }

            //write the data
            stream.Write(fileData, 0, fileData.Length);
            if (!hasNewLineCharEnding) {
                stream.Write(new byte[2] { (byte)'\r', (byte)'\n' }, 0, 2);
            }
        }

        //clean up
        stream.Close();
        return filename;
    }