/// <summary> /// Creates an instance of the second-pass assembler, /// which generates the code in the .text segment. /// </summary> /// <param name="symbolTable">The symbol table generated by the first-pass parser.</param> /// <param name="procFactory">The instruction processor factory to retrieve code generator implementations from.</param> public TextCodeGenerator(ILogger logger, SymbolTable symbolTable, InstructionProcessorFactory procFactory) { m_Logger = logger; m_ParserFac = procFactory; m_SymTbl = symbolTable; m_CurrTextAddress = CommonConstants.BASE_TEXT_ADDRESS; }
/// <summary> /// Creates a mapping to segment types to their declarations. /// Add future supported segment types here. /// </summary> /// <param name="procFactory">The instruction processor factory to retrieve instruction size estimator implementations from.</param> public SegmentSymbolParserFactory(InstructionProcessorFactory procFac) { m_ParserTable = new Dictionary <SegmentType, ISymbolTableBuilder>() { { SegmentType.Data, new DataSymbolBuilder() }, { SegmentType.Text, new TextSymbolBuilder(procFac) } }; }
/// <summary> /// Creates an instance of the CodeGeneratorFactory. /// </summary> /// <param name="logger">The logging implementation to use for logging warnings/information.</param> /// <param name="symTable">The populated symbol table.</param> /// <param name="procFactory">The instruction processor factory to retrieve code generator implementations from.</param> public CodeGeneratorFactory(ILogger logger, SymbolTable symTable, InstructionProcessorFactory procFactory) { m_CodeGeneratorTable = new Dictionary <SegmentType, ISegmentCodeGenerator>() { { SegmentType.Data, new DataCodeGenerator(symTable) }, { SegmentType.Text, new TextCodeGenerator(logger, symTable, procFactory) } }; }
private static (int acc, bool terminated) Execute(ImmutableArray <Instruction> instructions) { var lineExecutions = new bool[instructions.Length]; var acc = 0; var currentLine = 0; bool Terminated() => currentLine == instructions.Length; while (!Terminated() && !lineExecutions[currentLine]) { var(operation, argument) = instructions[currentLine]; var instructionProcessor = InstructionProcessorFactory.Get(operation); var(accAfter, lineAfter) = instructionProcessor.Evaluate(argument, acc, currentLine); lineExecutions[currentLine] = true; (acc, currentLine) = (accAfter, lineAfter); } return(acc, Terminated()); }
/// <summary> /// Creates an instance of the first pass assembler, which determines /// the locations of labels and generates a symbol table. /// </summary> /// <param name="logger">The logging implementation to use.</param> /// <param name="procFactory">The instruction processor factory to retrieve instruction size estimator implementations from.</param> public SymbolTableBuilder(ILogger logger, InstructionProcessorFactory procFac) { m_Logger = logger; m_SymbolBuilderFac = new SegmentSymbolParserFactory(procFac); m_CurrExternAddress = CommonConstants.BASE_EXTERN_ADDRESS; }
/// <summary> /// Creates a new instance of a CodeGenerator. /// </summary> /// <param name="logger">The logging implementation to use for logging warnings/information.</param> /// <param name="symTable">The symbol table to use to resolve references with.</param> /// <param name="procFactory">The instruction processor factory to retrieve code generator implementations from.</param> public CodeGenerator(ILogger logger, SymbolTable symTable, InstructionProcessorFactory procFac) { m_CodeGenFac = new CodeGeneratorFactory(logger, symTable, procFac); }
/// <summary> /// Creates a new instance of a text segment parser /// TODO: determine if signedness/unsignedness has any tangible effect /// on code generation. /// </summary> /// <param name="procFactory">The instruction processor factory to retrieve instruction size estimator implementations from.</param> public TextSymbolBuilder(InstructionProcessorFactory procFac) { m_CurrTextAddress = CommonConstants.BASE_TEXT_ADDRESS; m_SizeEstimatorFac = procFac; }
/// <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); }