/// <summary> /// Gets the appropriate file output format based on the file extension /// of the output file. /// </summary> /// <param name="filePath">The file path or name of the output file.</param> /// <returns>An appropriate instance of IObjectFileWriter for that particular /// file extension.</returns> public IObjectFileWriter GetWriterForOutputFile(string filePath) { string fileExtension = filePath.Substring(filePath.LastIndexOf('.')); IObjectFileWriter writer = default(IObjectFileWriter); if (fileExtension == ".jef") { writer = GetWriterForObjectType(OutputTypes.DirectBinary); } else { writer = GetWriterForObjectType(OutputTypes.ELF); } return(writer); }
/// <summary> /// Task for assembling one individual file. /// </summary> /// <param name="inputFile">The input file to assemble.</param> /// <param name="logger">The logging implementation to log errors/info to.</param> /// <param name="options">The options to use while assembling.</param> /// <returns>True if the assembler could successfully generate code for the file; otherwise returns false.</returns> public AssemblerResult AssembleFile(string inputFile, string outputFile, ILogger logger, AssemblerOptions options) { var result = new AssemblerResult(); logger.Log(LogLevel.Info, "Invoking assembler for file " + inputFile); try { bool furtherProcessingNeeded = true; if (File.Exists(inputFile) && File.Exists(outputFile)) { DateTime inputFileWriteTime = File.GetLastWriteTimeUtc(inputFile); DateTime outputFileWriteTime = File.GetLastWriteTimeUtc(outputFile); if (outputFileWriteTime > inputFileWriteTime) { logger.Log(LogLevel.Info, "Nothing to do for file " + inputFile); furtherProcessingNeeded = false; } } if (furtherProcessingNeeded) { using (var reader = new StreamReader(File.OpenRead(inputFile))) { var symTable = new SymbolTable(); // build the symbol table var instructionProcFac = new InstructionProcessorFactory(symTable); var symTableBuilder = new SymbolTableBuilder(logger, instructionProcFac); symTableBuilder.GenerateSymbolTableForSegment(reader, SegmentType.Data, symTable); symTableBuilder.GenerateSymbolTableForSegment(reader, SegmentType.Text, symTable); // use the symbol table to generate code with references resolved. var objFile = new BasicObjectFile(inputFile, symTable); var codeGenerator = new CodeGenerator(logger, symTable, instructionProcFac); codeGenerator.GenerateCode(inputFile, reader, objFile); if (!objFile.TextElements.Any()) { logger.Log(LogLevel.Warning, "No .text segment to assemble. Stop."); result.OperationSuccessful = false; } else { // write the object file out. var writerFac = new ObjectFileWriterFactory(); IObjectFileWriter writer = writerFac.GetWriterForOutputFile(outputFile); writer.WriteObjectFile(outputFile, objFile); } } } } catch (AggregateAssemblyError ex) { foreach (AssemblyException asEx in ex.AssemblyErrors) { logger.Log(LogLevel.Critical, "In file \"" + inputFile + "\" (line " + asEx.LineNumber + "):\n\t"); logger.Log(LogLevel.Critical, asEx.Message); result.AddUserAssemblyError(asEx); } } catch (Exception ex) { logger.Log(LogLevel.Critical, ex.StackTrace); logger.Log(LogLevel.Critical, ex.Message); if (ex.InnerException != null) { logger.Log(LogLevel.Critical, ex.InnerException.StackTrace); logger.Log(LogLevel.Critical, ex.InnerException.Message); } result.AddInternalAssemblerError(ex); } return(result); }