示例#1
0
        /// <summary>
        /// Begin the assembly process.
        /// </summary>
        /// <returns>The time in seconds for the assembly to complete.</returns>
        /// <exception cref="Exception"></exception>
        public double Assemble()
        {
            if (_services.Log.HasErrors)
            {
                _services.Log.DumpErrors();
                return(double.NaN);
            }
            if (_services.Options.InputFiles.Count == 0)
            {
                throw new Exception("One or more required input files was not specified.");
            }

            var stopWatch = new Stopwatch();

            stopWatch.Start();

            // process cmd line args
            if (_services.Options.Quiet)
            {
                Console.SetOut(TextWriter.Null);
            }

            var preprocessor = new Preprocessor(_processorOptions);
            var processed    = new List <SourceLine>();

            try
            {
                // preprocess all passed option defines and sections
                foreach (var define in _services.Options.LabelDefines)
                {
                    processed.Add(preprocessor.ProcessDefine(define));
                }
                foreach (var section in _services.Options.Sections)
                {
                    processed.AddRange(preprocessor.Process(string.Empty, processed.Count, $".dsection {section}"));
                }

                // preprocess all input files
                foreach (var inputFile in _services.Options.InputFiles)
                {
                    processed.AddRange(preprocessor.Process(inputFile));
                }

                if (!_services.Options.NoStats)
                {
                    Console.WriteLine($"{Assembler.AssemblerName}");
                    Console.WriteLine($"{Assembler.AssemblerVersion}");
                }
                var multiLineAssembler = new MultiLineAssembler()
                                         .WithAssemblers(_assemblers)
                                         .WithOptions(new MultiLineAssembler.Options
                {
                    AllowReturn     = false,
                    DisassembleAll  = _services.Options.VerboseList,
                    ErrorHandler    = AssemblyErrorHandler,
                    StopDisassembly = () => _services.PrintOff,
                    Evaluator       = _services.Evaluator
                });

                var disassembly = string.Empty;

                // while passes are needed
                while (_services.PassNeeded && !_services.Log.HasErrors)
                {
                    if (_services.DoNewPass() == 4)
                    {
                        throw new Exception("Too many passes attempted.");
                    }
                    _ = multiLineAssembler.AssembleLines(processed.GetIterator(), out disassembly);
                    if (!_services.PassNeeded && _services.CurrentPass == 0)
                    {
                        _services.PassNeeded = _services.SymbolManager.SearchedNotFound;
                    }
                }
                if (!_services.Options.WarnNotUnusedSections && !_services.Log.HasErrors)
                {
                    var unused = _services.Output.UnusedSections;
                    if (unused.Count() > 0)
                    {
                        foreach (var section in unused)
                        {
                            _services.Log.LogEntry(null, 1, 1,
                                                   $"Section {section} was defined but never used.", false);
                        }
                    }
                }
                if (!_services.Options.NoWarnings && _services.Log.HasWarnings)
                {
                    _services.Log.DumpWarnings();
                }
                int byteCount = 0;
                if (_services.Log.HasErrors)
                {
                    _services.Log.DumpErrors();
                }
                else
                {
                    var passedArgs = _services.Options.GetPassedArgs();
                    var exec       = Process.GetCurrentProcess().MainModule.ModuleName;
                    var inputFiles = string.Join("\n// ", preprocessor.GetInputFiles());
                    var fullDisasm = $"// {Assembler.AssemblerNameSimple}\n" +
                                     $"// {exec} {string.Join(' ', passedArgs)}\n" +
                                     $"// {DateTime.Now:f}\n\n// Input files:\n\n" +
                                     $"// {inputFiles}\n\n" + disassembly;
                    byteCount = WriteOutput(fullDisasm);
                }
                if (!_services.Options.NoStats)
                {
                    Console.WriteLine($"Number of errors: {_services.Log.ErrorCount}");
                    Console.WriteLine($"Number of warnings: {_services.Log.WarningCount}");
                }
                stopWatch.Stop();
                var ts = stopWatch.Elapsed.TotalSeconds;
                if (!_services.Log.HasErrors)
                {
                    var section = _services.Options.OutputSection;
                    if (!_services.Options.NoStats)
                    {
                        if (!string.IsNullOrEmpty(section))
                        {
                            Console.Write($"[{section}] ");
                        }

                        if (!string.IsNullOrEmpty(_services.Options.Patch))
                        {
                            Console.WriteLine($"{byteCount} (Offs:{_services.Options.Patch}), {ts} sec.");
                        }
                        else
                        {
                            Console.WriteLine($"{byteCount} bytes, {ts} sec.");
                        }
                        if (_services.Options.ShowChecksums)
                        {
                            Console.WriteLine($"Checksum: {_services.Output.GetOutputHash(section)}");
                        }
                        Console.WriteLine("*********************************");
                        Console.Write("Assembly completed successfully.");
                    }
                }
                else
                {
                    _services.Log.ClearAll();
                }
                return(ts);
            }
            catch (Exception ex)
            {
                _services.Log.LogEntrySimple(ex.Message);
                return(double.NaN);
            }
            finally
            {
                if (_services.Log.HasErrors)
                {
                    _services.Log.DumpErrors();
                }
            }
        }
示例#2
0
        /// <summary>
        /// Invokes the function from its definition, starting assembly at the first line.
        /// </summary>
        /// <param name="mla">The <see cref="MultiLineAssembler"/> reponsible for making
        /// the function call.</param>
        /// <param name="parameterList">The parameters of the function call.</param>
        /// <returns>A <see cref="double"/> of the function return.</returns>
        public double Invoke(MultiLineAssembler mla, List <object> parameterList)
        {
            var invokeLine = Assembler.LineIterator.Current;

            if (parameterList.Count > Params.Count)
            {
                Assembler.Log.LogEntry(invokeLine, invokeLine.Instruction, "Unexpected argument passed to function.");
                return(double.NaN);
            }
            for (var i = 0; i < Params.Count; i++)
            {
                if (i >= parameterList.Count || parameterList[i] == null)
                {
                    if (!string.IsNullOrEmpty(Params[i].DefaultValue))
                    {
                        Assembler.SymbolManager.Define(Params[i].Name, Evaluator.Evaluate(Params[i].DefaultValue), true);
                    }
                    else
                    {
                        Assembler.Log.LogEntry(invokeLine, invokeLine.Instruction,
                                               $"Missing argument \"{Params[i].Name}\" for function.");
                        return(double.NaN);
                    }
                }
                else
                {
                    var parm = parameterList[i];
                    if (parm.ToString().EnclosedInDoubleQuotes())
                    {
                        Assembler.SymbolManager.Define(Params[i].Name, parm.ToString().TrimOnce('"'), true);
                    }
                    else
                    {
                        Assembler.SymbolManager.Define(Params[i].Name, (double)parm, true);
                    }
                }
            }
            var assemblers = new List <AssemblerBase>
            {
                new AssignmentAssembler(),
                new EncodingAssembler(),
                new MiscAssembler(),
                mla
            };
            var returnIx = Assembler.LineIterator.Index;

            if (returnIx < StartIndex)
            {
                Assembler.LineIterator.FastForward(StartIndex);
            }
            else
            {
                Assembler.LineIterator.Rewind(StartIndex);
            }

            foreach (SourceLine line in Assembler.LineIterator)
            {
                if (Assembler.LineIterator.Index == EndIndex)
                {
                    break;
                }
                if (line.InstructionName.Equals(".return"))
                {
                    if (line.OperandHasToken)
                    {
                        return(Evaluator.Evaluate(line.Operand));
                    }
                    return(double.NaN);
                }
                var asm = assemblers.FirstOrDefault(asm => asm.AssemblesLine(line));
                if (asm == null && line.Instruction != null)
                {
                    Assembler.Log.LogEntry(line, line.Instruction,
                                           $"Directive \"{line.InstructionName}\" not allowed inside a function block.");
                    break;
                }
                else if (asm != null)
                {
                    asm.AssembleLine(line);
                    if (line.InstructionName.Equals(".goto") &&
                        (Assembler.LineIterator.Index < StartIndex || Assembler.LineIterator.Index > EndIndex))
                    {
                        Assembler.Log.LogEntry(line, line.Instruction,
                                               $"\".goto\" destination \"{line.OperandExpression}\" is outside of function block.");
                        break;
                    }
                }
            }
            return(double.NaN);
        }
示例#3
0
        /// <summary>
        /// Begin the assembly process.
        /// </summary>
        /// <exception cref="Exception"></exception>
        public void Assemble()
        {
            var stopWatch = new Stopwatch();

            stopWatch.Start();
            try
            {
                // process cmd line args
                if (Assembler.Options.Quiet)
                {
                    Console.SetOut(TextWriter.Null);
                }

                Console.WriteLine(Assembler.AssemblerName);
                Console.WriteLine(Assembler.AssemblerVersion);

                // init all line assemblers
                var multiLineAssembler = new MultiLineAssembler();

                _assemblers.Add(multiLineAssembler);
                _assemblers.Add(new AssignmentAssembler());
                _assemblers.Add(new EncodingAssembler());
                _assemblers.Add(new PseudoAssembler());
                _assemblers.Add(new MiscAssembler());

                // preprocess all input files
                var preprocessor = new Preprocessor();
                var processed    = new List <SourceLine>();

                // define all passed option defines
                if (Assembler.Options.LabelDefines.Count > 0)
                {
                    foreach (var define in Assembler.Options.LabelDefines)
                    {
                        processed.AddRange(preprocessor.PreprocessSource(define));
                    }
                }
                foreach (var path in Assembler.Options.InputFiles)
                {
                    processed.AddRange(preprocessor.PreprocessFile(path));
                }

                // set the iterator
                Assembler.LineIterator = processed.GetIterator();

                var exec         = Process.GetCurrentProcess().MainModule.ModuleName;
                var argsPassed   = string.Join(' ', Assembler.Options.Arguments);
                var inputFiles   = string.Join("\n// ", preprocessor.GetInputFiles());
                var disasmHeader = $"// {Assembler.AssemblerNameSimple}\n// {exec} {argsPassed}\n// {DateTime.Now:f}\n\n// Input files:" +
                                   $"\n\n// {inputFiles}\n\n";
                StringBuilder disassembly = null;
                // while passes are needed
                while (Assembler.PassNeeded && !Assembler.Log.HasErrors)
                {
                    if (Assembler.CurrentPass++ == 4)
                    {
                        throw new Exception("Too many passes attempted.");
                    }
                    disassembly = new StringBuilder(disasmHeader);
                    foreach (var line in Assembler.LineIterator)
                    {
                        try
                        {
                            if (line.Label != null || line.Instruction != null)
                            {
                                var asm = _assemblers.FirstOrDefault(a => a.AssemblesLine(line));
                                if (asm != null)
                                {
                                    var disasm = asm.AssembleLine(line);
                                    if (!string.IsNullOrWhiteSpace(disasm) && !Assembler.PrintOff)
                                    {
                                        disassembly.AppendLine(disasm);
                                    }
                                }
                                else if (line.Instruction != null)
                                {
                                    Assembler.Log.LogEntry(line,
                                                           line.Instruction.Position,
                                                           $"Unknown instruction \"{line.InstructionName}\".");
                                }
                            }
                            else if (Assembler.Options.VerboseList)
                            {
                                disassembly.AppendLine(line.UnparsedSource.PadLeft(50, ' '));
                            }
                        }
                        catch (Exception ex)
                        {
                            if (ex is SymbolException symbEx)
                            {
                                Assembler.Log.LogEntry(line, symbEx.Position, symbEx.Message, true);
                            }
                            else if (ex is FormatException fmtEx)
                            {
                                Assembler.Log.LogEntry(line,
                                                       line.Operand,
                                                       $"There was a problem with the format string:\n{fmtEx.Message}.",
                                                       true);
                            }
                            else if (Assembler.CurrentPass > 0 && !Assembler.PassNeeded)
                            {
                                if (ex is ExpressionException expEx)
                                {
                                    if (ex is IllegalQuantityException)
                                    {
                                        Assembler.Log.LogEntry(line, expEx.Position,
                                                               $"Illegal quantity for \"{line.Instruction}\" in expression \"{line.Operand}\".");
                                    }
                                    else
                                    {
                                        Assembler.Log.LogEntry(line, expEx.Position, ex.Message);
                                    }
                                }
                                else if (ex is OverflowException)
                                {
                                    Assembler.Log.LogEntry(line, line.Operand.Position,
                                                           $"Illegal quantity for \"{line.Instruction}\" in expression \"{line.Operand}\".");
                                }
                                else if (ex is InvalidPCAssignmentException pcEx)
                                {
                                    Assembler.Log.LogEntry(line, line.Instruction,
                                                           $"Invalid Program Counter assignment in expression \"{line.Operand}\".");
                                }
                                else if (ex is ProgramOverflowException prgEx)
                                {
                                    Assembler.Log.LogEntry(line, line.Instruction,
                                                           "Program Overflow.");
                                }
                                else
                                {
                                    Assembler.Log.LogEntry(line, line.Operand.Position, ex.Message);
                                }
                            }
                            else
                            {
                                Assembler.PassNeeded = true;
                            }
                        }
                    }
                    if (multiLineAssembler.InAnActiveBlock)
                    {
                        SourceLine activeLine = multiLineAssembler.ActiveBlockLine;
                        Assembler.Log.LogEntry(activeLine, activeLine.Instruction,
                                               $"End of source file reached before finding block closure for \"{activeLine.InstructionName}\".");
                    }
                    Assembler.LineIterator.Reset();
                }
                if (!Assembler.Options.NoWarnings && Assembler.Log.HasWarnings)
                {
                    Assembler.Log.DumpWarnings();
                }

                if (Assembler.Log.HasErrors)
                {
                    Assembler.Log.DumpErrors();
                }
                else
                {
                    WriteOutput(disassembly?.ToString());
                }

                Console.WriteLine($"Number of errors: {Assembler.Log.ErrorCount}");
                Console.WriteLine($"Number of warnings: {Assembler.Log.WarningCount}");

                if (!Assembler.Log.HasErrors)
                {
                    stopWatch.Stop();
                    var ts = stopWatch.Elapsed.TotalSeconds;

                    Console.WriteLine($"{Assembler.Output.GetCompilation().Count} bytes, {ts} sec.");
                    if (Assembler.Options.ShowChecksums)
                    {
                        Console.WriteLine($"Checksum: {Assembler.Output.GetOutputHash()}");
                    }
                    Console.WriteLine("*********************************");
                    Console.WriteLine("Assembly completed successfully.");
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.Message);
            }
        }