/// <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);
        }