Пример #1
0
 /// <summary>
 /// Creates a new instance of a page block processor.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 /// <param name="index">The index at which the block is defined.</param>
 public PageBlockProcessor(AssemblyServices services,
                           int index)
     : base(services, index, false)
 {
     Reserved.DefineType("Directives", ".page", ".endpage");
     _page = GetPage();
 }
Пример #2
0
        /// <summary>
        /// Creates a new instance of a switch block processor.
        /// </summary>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        /// <param name="index">The index at which the block is defined.</param>
        public SwitchBlock(AssemblyServices services,
                           int index)
            : base(services, index)
        {
            Reserved.DefineType("Directives", ".switch", ".case", ".default", ".endswitch");

            Reserved.DefineType("BreakContReturn", ".break", ".continue", ".return");
        }
Пример #3
0
        /// <summary>
        /// Gets a string from the tokenized expression.
        /// </summary>
        /// <param name="iterator">The iterator to the tokenized expression.</param>
        /// <param name="services">The shared assembly services.</param>
        /// <returns></returns>
        public static string GetString(RandomAccessIterator <Token> iterator, AssemblyServices services)
        {
            if (iterator.Current == null && !iterator.MoveNext())
            {
                return(string.Empty);
            }
            var token = iterator.Current;

            if (IsStringLiteral(iterator))
            {
                iterator.MoveNext();
                return(Regex.Unescape(token.Name.ToString()).TrimOnce('"'));
            }
            else if (token.Type == TokenType.Function && token.Name.Equals("format", services.StringComparison))
            {
                var str = GetFormatted(iterator, services);
                if (!string.IsNullOrEmpty(str) && Token.IsEnd(iterator.Current))
                {
                    return(str);
                }
            }
            else if (token.Type == TokenType.Function && token.Name.Equals("char", services.StringComparison))
            {
                var code = (int)services.Evaluator.Evaluate(iterator, 0, 0x10FFFF);
                return(char.ConvertFromUtf32(services.Encoding.GetCodePoint(code)));
            }
            else if (token.Type == TokenType.Operand &&
                     (char.IsLetter(token.Name[0]) || token.Name[0] == '_') &&
                     !services.Evaluator.IsReserved(token.Name))
            {
                var sym = services.SymbolManager.GetSymbol(token, services.CurrentPass > 0);
                if (sym == null)
                {
                    return(string.Empty);
                }
                if (sym.DataType == DataType.String)
                {
                    if ((!iterator.MoveNext() || Token.IsEnd(iterator.Current)) && sym.StorageType == StorageType.Scalar)
                    {
                        return(sym.StringValue.TrimOnce('"').ToString());
                    }
                    else if (sym.StorageType == StorageType.Vector && iterator.Current.Name.Equals("["))
                    {
                        var current   = iterator.Current;
                        var subscript = (int)services.Evaluator.Evaluate(iterator);
                        if (Token.IsEnd(iterator.Current))
                        {
                            if (subscript >= 0 && subscript < sym.StringVector.Count)
                            {
                                return(sym.StringVector[subscript].ToString());
                            }
                            throw new SyntaxException(current, "Index out of range.");
                        }
                    }
                }
            }
            throw new SyntaxException(token, "Type mismatch.");
        }
Пример #4
0
 /// <summary>
 /// Constructs an instance of the class implementing the base class.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 protected AssemblerBase(AssemblyServices services)
 {
     Services = services;
     ExcludedInstructionsForLabelDefines = new HashSet <StringView>(services.StringViewComparer);
     Reserved = new ReservedWords(services.StringViewComparer);
     services.IsReserved.Add(Reserved.IsReserved);
     services.SymbolManager.AddValidSymbolNameCriterion(s => !Reserved.IsReserved(s));
     services.InstructionLookupRules.Add(s => Assembles(s));
 }
Пример #5
0
 /// <summary>
 /// Creates a new instance of a block processor.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 /// <param name="index">The index at which the block is defined.</param>
 /// <param name="createScope">Automatically create a scope when initialized.</param>
 protected BlockProcessorBase(AssemblyServices services, int index, bool createScope)
     : base(services)
 {
     Index        = index;
     _createScope = createScope;
     if (_createScope)
     {
         services.SymbolManager.PushScope(Index.ToString());
     }
 }
Пример #6
0
 static CpuAssembler SetCpu(string cpu, AssemblyServices services)
 {
     return(cpu switch
     {
         "m6800" => new M6809Asm(services),
         "m6809" => new M6809Asm(services),
         "i8080" => new Z80Asm(services),
         "z80" => new Z80Asm(services),
         _ => new Asm6502(services)
     });
Пример #7
0
        /// <summary>
        /// Gets the formatted string from the tokenized expression.
        /// </summary>
        /// <param name="iterator">The iterator to the tokenized expression.</param>
        /// <param name="services">The shared assembly services.</param>
        /// <returns></returns>
        public static string GetFormatted(RandomAccessIterator <Token> iterator, AssemblyServices services)
        {
            iterator.MoveNext();
            var format = iterator.GetNext();

            if (Token.IsEnd(format))
            {
                return(null);
            }
            string fmt;

            if (!format.IsDoubleQuote())
            {
                if (format.Type != TokenType.Function && !format.Name.Equals("format", services.StringComparison))
                {
                    return(null);
                }
                fmt = GetFormatted(iterator, services);
            }
            else
            {
                fmt = Regex.Unescape(format.Name.TrimOnce('"').ToString());
            }
            var parms = new List <object>();

            if (iterator.MoveNext())
            {
                while (!Token.IsEnd(iterator.GetNext()))
                {
                    if (ExpressionIsAString(iterator, services))
                    {
                        parms.Add(GetString(iterator, services));
                    }
                    else
                    {
                        var parmVal = services.Evaluator.Evaluate(iterator, false);
                        if (Regex.IsMatch(fmt, $"\\{{{parms.Count}(,-?\\d+)?:(d|D|x|X)\\d*\\}}"))
                        {
                            parms.Add((int)parmVal);
                        }
                        else
                        {
                            parms.Add(parmVal);
                        }
                    }
                }
            }
            if (parms.Count == 0)
            {
                return(fmt);
            }
            return(string.Format(fmt, parms.ToArray()));
        }
Пример #8
0
 /// <summary>
 /// Constructs a DotNetAsm.MiscAssembler class.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 public MiscAssembler(AssemblyServices services)
     : base(services)
 {
     Reserved.DefineType("Directives",
                         ".assert", ".bank", ".end",
                         ".eor", ".echo", ".forcepass",
                         ".format", ".invoke",
                         ".initmem", ".target",
                         ".error", ".errorif",
                         ".pron", ".proff",
                         ".warnif", ".warn",
                         ".dsection", ".section"
                         );
     ExcludedInstructionsForLabelDefines.Add(".section");
     Services.PassChanged += (s, a) => Services.PrintOff = false;
 }
Пример #9
0
        /// <summary>
        /// Constructs an instance of a <see cref="PseudoAssembler"/> line assembler.
        /// </summary>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        public PseudoAssembler(AssemblyServices services)
            : base(services)
        {
            Reserved.DefineType("Types",
                                ".addr", ".align", ".binary", ".bstring", ".byte", ".sbyte",
                                ".char", ".dint", ".dword", ".fill", ".hstring", ".lint",
                                ".long", ".rta", ".short", ".sint", ".word",
                                ".cstring", ".lstring", ".nstring", ".pstring",
                                ".string", ".cbmflt", ".cbmfltp"
                                );

            Reserved.DefineType("Functions",
                                "cbmflt", "cbmfltp", "char", "format", "peek", "poke", "section"
                                );
            services.Evaluator.AddFunctionEvaluator(this);
            _includedBinaries = new Dictionary <StringView, BinaryFile>(services.StringViewComparer);
        }
Пример #10
0
        /// <summary>
        /// Creates a new instance of the Function class.
        /// </summary>
        /// <param name="name">The function's name.</param>
        /// <param name="parameterList">The list of parameters for the function.</param>
        /// <param name="iterator">The <see cref="SourceLine"/> iterator to traverse to define the function block.</param>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        /// <param name="caseSensitive">Determines whether to compare the passed parameters
        /// to the source block's own defined parameters should be case-sensitive.</param>
        /// <exception cref="SyntaxException"></exception>
        public Function(StringView name,
                        List <Token> parameterList,
                        RandomAccessIterator <SourceLine> iterator,
                        AssemblyServices services,
                        bool caseSensitive)
            : base(parameterList,
                   caseSensitive)
        {
            Name          = name;
            _services     = services;
            _definedLines = new List <SourceLine>();
            SourceLine line;

            while ((line = iterator.GetNext()) != null)
            {
                if (line.Label != null && line.Label.Name.Equals("+"))
                {
                    _services.Log.LogEntry(line.Label,
                                           "Anonymous labels are not supported inside functions.", false);
                }
                if (line.Instruction != null)
                {
                    if (line.Instruction.Name.Equals(".global", _services.StringViewComparer))
                    {
                        throw new SyntaxException(line.Instruction,
                                                  $"Directive \".global\" not allowed inside a function block.");
                    }
                    if (line.Instruction.Name.Equals(".endfunction", _services.StringViewComparer))
                    {
                        if (line.Operands.Count > 0)
                        {
                            throw new SyntaxException(line.Operands[0],
                                                      "Unexpected expression found after \".endfunction\" directive.");
                        }
                        break;
                    }
                }
                _definedLines.Add(line);
            }
            if (line == null)
            {
                throw new SyntaxException(iterator.Current.Instruction,
                                          "Function definition does not have a closing \".endfunction\" directive.");
            }
        }
Пример #11
0
        /// <summary>
        /// Creates a new instance of a conditional block processor.
        /// </summary>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        /// <param name="index">The index at which the block is defined.</param>
        public ConditionalBlock(AssemblyServices services, int index)
            : base(services, index, false)
        {
            _opens = new HashSet <string>(services.StringComparer)
            {
                ".if", ".ifdef", ".ifndef"
            };
            Reserved.DefineType("Keywords",
                                ".if", ".ifdef", ".ifndef", ".else", ".elseif",
                                ".elseif", ".elseifdef", ".elseifndef", ".endif");

            Reserved.DefineType("Defs",
                                ".ifdef", ".ifndef");

            _ifDefEvaluations  = new Dictionary <(string, int), bool>();
            _ifTrue            =
                _elseEvaluated = false;
        }
Пример #12
0
        /// <summary>
        /// Constructs a new instance of a block assembler.
        /// </summary>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        public BlockAssembler(AssemblyServices services)
            : base(services)
        {
            _blocks       = new Stack <BlockProcessorBase>();
            _functionDefs = new Dictionary <StringView, Function>(services.StringViewComparer);

            _currentBlock = null;

            _openClosures = new Dictionary <StringView, StringView>(services.StringViewComparer)
            {
                { ".block", ".endblock" },
                { ".for", ".next" },
                { ".foreach", ".next" },
                { ".function", ".endfunction" },
                { ".if", ".endif" },
                { ".ifdef", ".endif" },
                { ".ifndef", ".endif" },
                { ".namespace", ".endnamespace" },
                { ".page", ".endpage" },
                { ".repeat", ".endrepeat" },
                { ".switch", ".endswitch" },
                { ".while", ".endwhile" }
            };

            Reserved.DefineType("Functional",
                                ".function", ".endfunction");

            Reserved.DefineType("NonOpens",
                                ".break", ".case", ".continue", ".default", ".endblock", ".endif",
                                ".endfunction", ".endpage", ".endnamespace", ".endrepeat", ".endswitch",
                                ".endwhile", ".else", ".elseif", ".elseifdef", ".elseifdef", ".elseifndef", ".next");

            Reserved.DefineType("BreakContinue", ".break", ".continue");

            Reserved.DefineType("Goto", ".goto");

            ExcludedInstructionsForLabelDefines.Add(".function");
            ExcludedInstructionsForLabelDefines.Add(".block");

            Services.Evaluator.AddFunctionEvaluator(this);

            Services.IsReserved.Add(s => _functionDefs.ContainsKey(s));
        }
Пример #13
0
        /// <summary>
        /// Constructs a new instance of the assignment assembler class.
        /// </summary>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        public AssignmentAssembler(AssemblyServices services)
            : base(services)
        {
            Reserved.DefineType("Assignments", ".equ", ".global", "=");

            Reserved.DefineType("Pseudo",
                                ".relocate", ".pseudopc", ".endrelocate", ".realpc");

            Reserved.DefineType("Directives", ".let", ".org");

            Reserved.DefineType("Functions", "len");

            ExcludedInstructionsForLabelDefines.Add(".org");
            ExcludedInstructionsForLabelDefines.Add(".equ");
            ExcludedInstructionsForLabelDefines.Add("=");
            ExcludedInstructionsForLabelDefines.Add(".global");

            Services.Evaluator.AddFunctionEvaluator(this);
        }
Пример #14
0
        /// <summary>
        /// Constructs a new instance of a CPU assembler.
        /// </summary>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        protected CpuAssembler(AssemblyServices services)
            : base(services)
        {
            Reserved.DefineType("CPU", ".cpu");
            if (!string.IsNullOrEmpty(Services.CPU))
            {
                CPU = Services.CPU;
            }
            else
            {
                _cpu = string.Empty;
            }
            _initCpu = _cpu;
            OnSetCpu();

            Evaluations = new double[]
            {
                double.NaN, double.NaN, double.NaN
            };
        }
Пример #15
0
 /// <summary>
 /// Creates a new instance of a while block processor.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 /// <param name="index">The index at which the block is defined.</param>
 public WhileBlock(AssemblyServices services, int index)
     : base(services, index) => Reserved.DefineType("Directives", ".while", ".endwhile");
Пример #16
0
        /// <summary>
        /// Determines whether the tokenized expression is a string.
        /// </summary>
        /// <param name="iterator">The iterator to the tokenized expression.</param>
        /// <param name="services">The shared assembly services.</param>
        /// <returns></returns>
        public static bool ExpressionIsAString(RandomAccessIterator <Token> iterator, AssemblyServices services)
        {
            var token = iterator.Current;

            if (token.IsDoubleQuote())
            {
                return(token.Name.Length > 2 && Token.IsEnd(iterator.PeekNext()));
            }
            var ix     = iterator.Index;
            var result = false;

            if (token.Type == TokenType.Function &&
                (token.Name.Equals("format", services.StringComparison) || token.Name.Equals("char", services.StringComparison)))
            {
                iterator.MoveNext();
                var parms = Token.GetGroup(iterator);
                var last  = iterator.Current;
                result = Token.IsEnd(last);
                if (token.Name.Equals("char", services.StringComparison))
                {
                    result &= services.Evaluator.Evaluate(parms.GetIterator(), 0, 0x10FFFF).IsInteger();
                }
            }
            else if (token.Type == TokenType.Operand &&
                     (char.IsLetter(token.Name[0]) || token.Name[0] == '_') &&
                     !services.Evaluator.IsReserved(token.Name))
            {
                var sym = services.SymbolManager.GetSymbol(token, false);
                if (sym != null)
                {
                    if (iterator.MoveNext() && iterator.Current.Name.Equals("["))
                    {
                        var subscript = (int)services.Evaluator.Evaluate(iterator);
                        result = Token.IsEnd(iterator.Current) &&
                                 subscript >= 0 && subscript < sym.StringVector.Count;
                    }
                    else
                    {
                        result = Token.IsEnd(iterator.Current) &&
                                 sym.StorageType == StorageType.Scalar &&
                                 sym.DataType == DataType.String;
                    }
                }
            }
            iterator.SetIndex(ix);
            return(result);
        }
Пример #17
0
 /// <summary>
 /// Creates a new instance of a scoped block processor.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 /// <param name="index">The index at which the block is defined.</param>
 public ScopeBlock(AssemblyServices services, int index)
     : base(services, index, false) => Reserved.DefineType("Directives", ".block", ".endblock");
Пример #18
0
 /// <summary>
 /// Creates a new instance of a repeat block processor.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 /// <param name="index">The index at which the block is defined.</param>
 public RepeatBlock(AssemblyServices services, int index)
     : base(services, index) => Reserved.DefineType("Directives", ".repeat", ".endrepeat");
Пример #19
0
        /// <summary>
        /// Constructs a new instance of an <see cref="AssemblyController"/>, which controls
        /// the assembly process.
        /// </summary>
        /// <param name="args">The commandline arguments.</param>
        /// <param name="cpuSetHandler">The <see cref="CpuAssembler"/> selection handler.</param>
        /// <param name="formatSelector">The format selector.</param>
        /// <exception cref="ArgumentNullException"></exception>
        public AssemblyController(IEnumerable <string> args,
                                  Func <string, AssemblyServices, CpuAssembler> cpuSetHandler,
                                  Func <string, string, IBinaryFormatProvider> formatSelector)
        {
            if (args == null || cpuSetHandler == null || formatSelector == null)
            {
                throw new ArgumentNullException();
            }
            _services                = new AssemblyServices(Options.FromArgs(args));
            _services.PassChanged   += (s, a) => _services.Output.Reset();
            _services.PassChanged   += (s, a) => _services.SymbolManager.Reset();
            _services.FormatSelector = formatSelector;
            _processorOptions        = new ProcessorOptions
            {
                CaseSensitive       = _services.Options.CaseSensitive,
                Log                 = _services.Log,
                IncludePath         = _services.Options.IncludePath,
                IgnoreCommentColons = _services.Options.IgnoreColons,
                WarnOnLabelLeft     = _services.Options.WarnLeft,
                InstructionLookup   = symbol => _services.InstructionLookupRules.Any(ilr => ilr(symbol))
            };
            CpuAssembler cpuAssembler = null;
            var          cpu          = _services.Options.CPU;

            if (!string.IsNullOrEmpty(cpu))
            {
                cpuAssembler = cpuSetHandler(cpu, _services);
            }
            if (_services.Options.InputFiles.Count > 0)
            {
                var src = new Preprocessor(_processorOptions).ProcessToFirstDirective(_services.Options.InputFiles[0]);
                if (src != null && src.Instruction != null && src.Instruction.Name.Equals(".cpu", _services.StringViewComparer))
                {
                    if (src.Operands.Count != 1 || !src.Operands[0].IsDoubleQuote())
                    {
                        _services.Log.LogEntry(src.Filename, src.LineNumber, src.Instruction.Position,
                                               "Invalid expression for directive \".cpu\".");
                    }
                    else
                    {
                        cpu = src.Operands[0].Name.ToString().TrimOnce('"');
                    }
                }
            }
            _services.CPU = cpu;
            if (!string.IsNullOrEmpty(cpu) && cpuAssembler != null && !cpuAssembler.IsCpuValid(cpu))
            {
                _services.Log.LogEntrySimple($"Invalid CPU \"{cpu}\" specified.");
            }
            else
            {
                if (cpuAssembler == null)
                {
                    cpuAssembler = cpuSetHandler(cpu, _services);
                }
                _assemblers = new List <AssemblerBase>
                {
                    new AssignmentAssembler(_services),
                    new BlockAssembler(_services),
                    new EncodingAssembler(_services),
                    new PseudoAssembler(_services),
                    new MiscAssembler(_services),
                    cpuAssembler
                };
                _processorOptions.IsMacroNameValid = symbol => !_assemblers.Any(asm => asm.Assembles(symbol));
                _processorOptions.LineTerminates   = _services.LineTerminates;
            }
        }
Пример #20
0
 /// <summary>
 /// Creates a new instance of the for next block processor.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 /// <param name="index">The index at which the block is defined.</param>
 public ForNextBlock(AssemblyServices services, int index)
     : base(services, index) => Reserved.DefineType("Directives", ".for", ".next");
Пример #21
0
 /// <summary>
 /// Creates a new instance of a function block processor placeholder.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 /// <param name="index">The index at which the block is defined.</param>
 public FunctionBlock(AssemblyServices services, int index)
     : base(services, index)
 {
 }
Пример #22
0
 /// <summary>
 /// Creates a new instance of a block processor.
 /// </summary>
 /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
 /// <param name="index">The index at which the block is defined.</param>
 public BlockProcessorBase(AssemblyServices services, int index)
     : this(services, index, true)
 {
 }