/// <summary>
        /// Returns a visitor with the results of a single parsing pass
        /// </summary>
        /// <param name="textToParse">Z80 assembly code to parse</param>
        /// <param name="expectedErrors">Number of errors expected</param>
        /// <returns>
        /// Visitor with the syntax tree
        /// </returns>
        protected virtual ExpressionNode ParseExpr(string textToParse, int expectedErrors = 0)
        {
            var inputStream = new AntlrInputStream(textToParse);
            var lexer       = new Z80AsmLexer(inputStream);
            var tokenStream = new CommonTokenStream(lexer);
            var parser      = new Z80AsmParser(tokenStream);
            var context     = parser.expr();
            var visitor     = new Z80AsmVisitor();

            parser.SyntaxErrors.Count.ShouldBe(expectedErrors);
            return((ExpressionNode)visitor.VisitExpr(context));
        }
        /// <summary>
        /// Returns a visitor with the results of a single parsing pass
        /// </summary>
        /// <param name="textToParse">Z80 assembly code to parse</param>
        /// <returns>
        /// Visitor with the syntax tree
        /// </returns>
        protected virtual List <Z80AsmParserErrorInfo> ParseWithErrors(string textToParse)
        {
            var inputStream = new AntlrInputStream(textToParse);
            var lexer       = new Z80AsmLexer(inputStream);
            var tokenStream = new CommonTokenStream(lexer);
            var parser      = new Z80AsmParser(tokenStream);
            var context     = parser.compileUnit();
            var visitor     = new Z80AsmVisitor();

            visitor.Visit(context);
            return(parser.SyntaxErrors);
        }
Beispiel #3
0
        /// <summary>
        /// Visits the source code
        /// </summary>
        /// <param name="source">Source code string</param>
        /// <returns>Source code visitor object</returns>
        public static Z80AsmVisitor VisitSource(string source)
        {
            var inputStream = new AntlrInputStream(source);
            var lexer       = new Z80AsmLexer(inputStream);
            var tokenStream = new CommonTokenStream(lexer);
            var parser      = new Z80AsmParser(tokenStream);
            var context     = parser.compileUnit();
            var visitor     = new Z80AsmVisitor(inputStream);

            visitor.Visit(context);
            return(visitor);
        }
        /// <summary>
        /// Returns a visitor with the results of a single parsing pass
        /// </summary>
        /// <param name="textToParse">Z80 assembly code to parse</param>
        /// <returns>
        /// Visitor with the syntax tree
        /// </returns>
        private Z80AsmVisitor ParseAsmLine(string textToParse)
        {
            var inputStream = new AntlrInputStream(textToParse);
            var lexer       = new Z80AsmLexer(inputStream);
            var tokenStream = new CommonTokenStream(lexer);
            var parser      = new Z80AsmParser(tokenStream);
            var context     = parser.asmline();
            var visitor     = new Z80AsmVisitor();

            visitor.Visit(context);
            return(visitor);
        }
        /// <summary>
        /// Returns a visitor with the results of a single parsing pass
        /// </summary>
        /// <param name="textToParse">Z80 assembly code to parse</param>
        /// <param name="expectedErrors">Number of errors expected</param>
        /// <returns>
        /// Visitor with the syntax tree
        /// </returns>
        protected virtual Z80AsmVisitor Parse(string textToParse, int expectedErrors = 0)
        {
            var inputStream = new AntlrInputStream(textToParse);
            var lexer       = new Z80AsmLexer(inputStream);
            var tokenStream = new CommonTokenStream(lexer);
            var parser      = new Z80AsmParser(tokenStream);
            var context     = parser.compileUnit();
            var visitor     = new Z80AsmVisitor();

            visitor.Visit(context);
            parser.SyntaxErrors.Count.ShouldBe(expectedErrors);

            return(visitor);
        }
        /// <summary>
        /// Gets all the tags that intersect the specified spans.
        /// </summary>
        /// <param name="spans">The spans to visit.</param>
        /// <returns>
        /// A <see cref="T:Microsoft.VisualStudio.Text.Tagging.TagSpan`1" /> for each tag.
        /// </returns>
        public IEnumerable <ITagSpan <TextMarkerTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            // --- Go through the tags
            foreach (var curSpan in spans)
            {
                var firstLineNo = curSpan.Start.GetContainingLine().LineNumber;
                var lastLineNo  = curSpan.End.GetContainingLine().LineNumber;
                foreach (var line in SourceBuffer.CurrentSnapshot.Lines)
                {
                    if (line.LineNumber < firstLineNo || line.LineNumber > lastLineNo)
                    {
                        continue;
                    }

                    var textOfLine = line.GetText();

                    // --- Let's use the Z80 assembly parser to obtain tags
                    var inputStream = new AntlrInputStream(textOfLine);
                    var lexer       = new Z80AsmLexer(inputStream);
                    var tokenStream = new CommonTokenStream(lexer);
                    var parser      = new Z80AsmParser(tokenStream);
                    var context     = parser.asmline();
                    var visitor     = new Z80AsmVisitor(inputStream);
                    visitor.Visit(context);
                    if (!(visitor.LastAsmLine is SourceLineBase asmline))
                    {
                        continue;
                    }

                    var package = SpectNetPackage.Default;
                    if (package != null &&
                        string.Compare(package.DebugInfoProvider.CurrentBreakpointFile, FilePath,
                                       StringComparison.InvariantCultureIgnoreCase) == 0 &&
                        package.DebugInfoProvider.CurrentBreakpointLine - 1 == line.LineNumber)
                    {
                        // --- Check for the current breakpoint
                        yield return(CreateSpan(line,
                                                Package.Options.FullLineHighlight
                                ? new TextSpan(0, textOfLine.Length) : asmline.InstructionSpan,
                                                Z80AsmClassificationTypes.Z80_CURRENT_BREAKPOINT));
                    }
                }
            }
        }
        /// <summary>
        /// Gets all the tags that intersect the specified spans.
        /// </summary>
        /// <param name="spans">The spans to visit.</param>
        /// <returns>
        /// A <see cref="T:Microsoft.VisualStudio.Text.Tagging.TagSpan`1" /> for each tag.
        /// </returns>
        public IEnumerable <ITagSpan <Z80DebugTokenTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            // --- Go through the tags
            foreach (var curSpan in spans)
            {
                var firstLineNo = curSpan.Start.GetContainingLine().LineNumber;
                var lastLineNo  = curSpan.End.GetContainingLine().LineNumber;
                foreach (var line in SourceBuffer.CurrentSnapshot.Lines)
                {
                    if (line.LineNumber < firstLineNo || line.LineNumber > lastLineNo)
                    {
                        continue;
                    }

                    var textOfLine = line.GetText();

                    // --- Let's use the Z80 assembly parser to obtain tags
                    var inputStream = new AntlrInputStream(textOfLine);
                    var lexer       = new Z80AsmLexer(inputStream);
                    var tokenStream = new CommonTokenStream(lexer);
                    var parser      = new Z80AsmParser(tokenStream);
                    var context     = parser.asmline();
                    var visitor     = new Z80AsmVisitor();
                    visitor.Visit(context);
                    if (!(visitor.LastAsmLine is SourceLineBase asmline))
                    {
                        continue;
                    }

                    if (_currentBreakpointLine == line.LineNumber)
                    {
                        // --- Check for the current breakpoint
                        yield return(CreateSpan(line,
                                                Package.Options.FullLineHighlight
                                ? new TextSpan(0, textOfLine.Length) : asmline.InstructionSpan,
                                                "Z80CurrentBreakpoint"));
                    }
                }
            }
        }
        /// <summary>
        /// Gets all the tags that intersect the specified spans.
        /// </summary>
        /// <param name="spans">The spans to visit.</param>
        /// <returns>
        /// A <see cref="T:Microsoft.VisualStudio.Text.Tagging.TagSpan`1" /> for each tag.
        /// </returns>
        public IEnumerable <ITagSpan <Z80AsmTokenTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            // --- Obtain the breakpoints that may affect this view
            var affectedLines = new List <int>();

            if (Package != null)
            {
                foreach (Breakpoint bp in Package.ApplicationObject.Debugger.Breakpoints)
                {
                    if (string.Compare(bp.File, FilePath, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        // --- Breakpoints start lines at 1, ITextBuffer starts from 0
                        affectedLines.Add(bp.FileLine - 1);
                    }
                }
            }

            foreach (var curSpan in spans)
            {
                var currentLine = curSpan.Start.GetContainingLine();
                var textOfLine  = currentLine.GetText();

                // --- Just to be sure...
                if (textOfLine == null)
                {
                    yield break;
                }

                // --- Let's use the Z80 assembly parser to obtain tags
                var inputStream = new AntlrInputStream(textOfLine);
                var lexer       = new Z80AsmLexer(inputStream);
                var tokenStream = new CommonTokenStream(lexer);
                var parser      = new Z80AsmParser(tokenStream);
                var context     = parser.asmline();
                var visitor     = new Z80AsmVisitor();
                visitor.Visit(context);

                // --- Check for a block comment
                var lastStartIndex = 0;
                while (true)
                {
                    var blockBeginsPos = textOfLine.IndexOf("/*", lastStartIndex, StringComparison.Ordinal);
                    if (blockBeginsPos < 0)
                    {
                        break;
                    }
                    var blockEndsPos = textOfLine.IndexOf("*/", blockBeginsPos, StringComparison.Ordinal);
                    if (blockEndsPos <= blockBeginsPos)
                    {
                        break;
                    }

                    // --- Block comment found
                    lastStartIndex = blockEndsPos + 2;
                    yield return(CreateSpan(currentLine, new TextSpan(blockBeginsPos, blockEndsPos + 2), Z80AsmTokenType.Comment));
                }

                // --- No code line, no tagging
                if (!(visitor.LastAsmLine is SourceLineBase asmline))
                {
                    continue;
                }

                if (asmline is EmittingOperationBase && asmline.InstructionSpan != null)
                {
                    // --- This line contains executable instruction,
                    // --- So it might have a breakpoint
                    if (affectedLines.IndexOf(currentLine.LineNumber) >= 0)
                    {
                        // --- Check for the any preset breakpoint
                        yield return(CreateSpan(currentLine, asmline.InstructionSpan, Z80AsmTokenType.Breakpoint));
                    }
                }

                if (asmline.LabelSpan != null)
                {
                    // --- Retrieve a label
                    yield return(CreateSpan(currentLine, asmline.LabelSpan, Z80AsmTokenType.Label));
                }

                if (asmline.KeywordSpan != null)
                {
                    var type = Z80AsmTokenType.Instruction;
                    switch (asmline)
                    {
                    case PragmaBase _:
                        type = Z80AsmTokenType.Pragma;
                        break;

                    case Directive _:
                        type = Z80AsmTokenType.Directive;
                        break;

                    case IncludeDirective _:
                        type = Z80AsmTokenType.Include;
                        break;

                    case MacroOrStructInvocation _:
                        type = Z80AsmTokenType.MacroInvocation;
                        break;

                    case ModuleStatement _:
                    case ModuleEndStatement _:
                        type = Z80AsmTokenType.ModuleKeyword;
                        break;

                    case StatementBase _:
                        type = Z80AsmTokenType.Statement;
                        break;
                    }

                    // --- Retrieve a pragma/directive/instruction
                    yield return(CreateSpan(currentLine, asmline.KeywordSpan, type));
                }

                if (asmline.CommentSpan != null)
                {
                    yield return(CreateSpan(currentLine, asmline.CommentSpan, Z80AsmTokenType.Comment));
                }

                if (asmline.NumberSpans != null)
                {
                    foreach (var numberSpan in asmline.NumberSpans)
                    {
                        yield return(CreateSpan(currentLine, numberSpan, Z80AsmTokenType.Number));
                    }
                }

                if (asmline.StringSpans != null)
                {
                    foreach (var stringSpan in asmline.StringSpans)
                    {
                        yield return(CreateSpan(currentLine, stringSpan, Z80AsmTokenType.String));
                    }
                }

                if (asmline.FunctionSpans != null)
                {
                    foreach (var functionSpan in asmline.FunctionSpans)
                    {
                        yield return(CreateSpan(currentLine, functionSpan, Z80AsmTokenType.Function));
                    }
                }

                if (asmline.SemiVarSpans != null)
                {
                    foreach (var semiVarSpan in asmline.SemiVarSpans)
                    {
                        yield return(CreateSpan(currentLine, semiVarSpan, Z80AsmTokenType.SemiVar));
                    }
                }

                if (asmline.MacroParamSpans != null)
                {
                    foreach (var macroParamSpan in asmline.MacroParamSpans)
                    {
                        yield return(CreateSpan(currentLine, macroParamSpan, Z80AsmTokenType.MacroParam));
                    }
                }

                if (asmline.IdentifierSpans != null)
                {
                    foreach (var id in asmline.IdentifierSpans)
                    {
                        yield return(CreateSpan(currentLine, id, Z80AsmTokenType.Identifier));
                    }
                }

                if (asmline.StatementSpans != null)
                {
                    foreach (var statement in asmline.StatementSpans)
                    {
                        yield return(CreateSpan(currentLine, statement, Z80AsmTokenType.Statement));
                    }
                }

                if (asmline.OperandSpans != null)
                {
                    foreach (var operand in asmline.OperandSpans)
                    {
                        yield return(CreateSpan(currentLine, operand, Z80AsmTokenType.Operand));
                    }
                }

                if (asmline.MnemonicSpans != null)
                {
                    foreach (var mnemonic in asmline.MnemonicSpans)
                    {
                        yield return(CreateSpan(currentLine, mnemonic, Z80AsmTokenType.Instruction));
                    }
                }
            }
        }
Beispiel #9
0
        /// <summary>
        /// Parses the source code passed to the compiler
        /// </summary>
        /// <param name="fileIndex">Source file index</param>
        /// <param name="sourceItem">Source file item</param>
        /// <param name="sourceText">Source text to parse</param>
        /// <param name="parsedLines"></param>
        /// <returns>True, if parsing was successful</returns>
        private bool ExecuteParse(int fileIndex, SourceFileItem sourceItem, string sourceText,
                                  out List <SourceLineBase> parsedLines)
        {
            // --- No lines has been parsed yet
            parsedLines = new List <SourceLineBase>();

            // --- Parse all source codelines
            var inputStream = new AntlrInputStream(sourceText);
            var lexer       = new Z80AsmLexer(inputStream);
            var tokenStream = new CommonTokenStream(lexer);
            var parser      = new Z80AsmParser(tokenStream);
            var context     = parser.compileUnit();
            var visitor     = new Z80AsmVisitor();

            visitor.Visit(context);
            var visitedLines = visitor.Compilation;

            // --- Store any tasks defined by the user
            StoreTasks(sourceItem, visitedLines.Lines);

            // --- Collect syntax errors
            foreach (var error in parser.SyntaxErrors)
            {
                ReportError(sourceItem, error);
            }

            // --- Exit if there are any errors
            if (_output.ErrorCount != 0)
            {
                return(false);
            }

            // --- Now, process directives and the .model pragma
            var currentLineIndex = 0;
            var ifdefStack       = new Stack <bool?>();
            var processOps       = true;

            parsedLines = new List <SourceLineBase>();

            // --- Traverse through parsed lines
            var includeIndex = fileIndex;

            while (currentLineIndex < visitedLines.Lines.Count)
            {
                var line = visitedLines.Lines[currentLineIndex];
                if (line is ModelPragma modelPragma)
                {
                    ProcessModelPragma(modelPragma);
                }
                else if (line is IncludeDirective incDirective)
                {
                    includeIndex++;
                    // --- Parse the included file
                    if (ApplyIncludeDirective(includeIndex, incDirective, sourceItem,
                                              out var includedLines))
                    {
                        // --- Add the parse result of the include file to the result
                        parsedLines.AddRange(includedLines);
                    }
                }
                else if (line is Directive preProc)
                {
                    ApplyDirective(preProc, ifdefStack, ref processOps);
                }
                else if (processOps)
                {
                    line.FileIndex = fileIndex;
                    parsedLines.Add(line);
                }
                currentLineIndex++;
            }

            // --- Check if all #if and #ifdef has a closing #endif tag
            if (ifdefStack.Count > 0 && visitedLines.Lines.Count > 0)
            {
                ReportError(Errors.Z0062, visitedLines.Lines.Last());
            }

            return(_output.ErrorCount == 0);
        }
Beispiel #10
0
        /// <summary>
        /// Gets all the tags that intersect the specified spans.
        /// </summary>
        /// <param name="spans">The spans to visit.</param>
        /// <returns>
        /// A <see cref="T:Microsoft.VisualStudio.Text.Tagging.TagSpan`1" /> for each tag.
        /// </returns>
        public IEnumerable <ITagSpan <Z80AsmTokenTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            // --- Obtain the breakpoints that may affect this view
            var affectedLines = new List <int>();

            foreach (Breakpoint bp in Package.ApplicationObject.Debugger.Breakpoints)
            {
                if (string.Compare(bp.File, FilePath, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    // --- Breakpoints start lines at 1, ITextBuffer starts from 0
                    affectedLines.Add(bp.FileLine - 1);
                }
            }

            foreach (var curSpan in spans)
            {
                var currentLine = curSpan.Start.GetContainingLine();
                var textOfLine  = currentLine.GetText();

                // --- Let's use the Z80 assembly parser to obtain tags
                var inputStream = new AntlrInputStream(textOfLine);
                var lexer       = new Z80AsmLexer(inputStream);
                var tokenStream = new CommonTokenStream(lexer);
                var parser      = new Z80AsmParser(tokenStream);
                var context     = parser.asmline();
                var visitor     = new Z80AsmVisitor();
                visitor.Visit(context);
                if (!(visitor.LastAsmLine is SourceLineBase asmline))
                {
                    continue;
                }

                if (asmline is EmittingOperationBase && asmline.InstructionSpan != null)
                {
                    // --- This line contains executable instruction,
                    // --- So it might have a breakpoint
                    if (affectedLines.IndexOf(currentLine.LineNumber) >= 0)
                    {
                        // --- Check for the any preset breakpoint
                        yield return(CreateSpan(currentLine, asmline.InstructionSpan, Z80AsmTokenType.Breakpoint));
                    }
                }

                if (asmline.LabelSpan != null)
                {
                    // --- Retrieve a label
                    yield return(CreateSpan(currentLine, asmline.LabelSpan, Z80AsmTokenType.Label));
                }

                if (asmline.KeywordSpan != null)
                {
                    var type = Z80AsmTokenType.Instruction;
                    if (asmline is PragmaBase)
                    {
                        type = Z80AsmTokenType.Pragma;
                    }
                    else if (asmline is Directive)
                    {
                        type = Z80AsmTokenType.Directive;
                    }
                    else if (asmline is IncludeDirective)
                    {
                        type = Z80AsmTokenType.Include;
                    }

                    // --- Retrieve a pragma/directive/instruction
                    yield return(CreateSpan(currentLine, asmline.KeywordSpan, type));
                }

                if (asmline.CommentSpan != null)
                {
                    // --- Retrieve a comment
                    yield return(CreateSpan(currentLine, asmline.CommentSpan, Z80AsmTokenType.Comment));
                }

                if (asmline.Numbers != null)
                {
                    foreach (var numberSpan in asmline.Numbers)
                    {
                        // --- Retrieve a number
                        yield return(CreateSpan(currentLine, numberSpan, Z80AsmTokenType.Number));
                    }
                }

                if (asmline.Identifiers == null)
                {
                    continue;
                }

                foreach (var idSpan in asmline.Identifiers)
                {
                    // --- Retrieve a number
                    yield return(CreateSpan(currentLine, idSpan, Z80AsmTokenType.Identifier));
                }
            }
        }
Beispiel #11
0
        /// <summary>
        /// Parses the source code passed to the compiler
        /// </summary>
        /// <param name="fileIndex">Source file index</param>
        /// <param name="sourceItem">Source file item</param>
        /// <param name="sourceText">Source text to parse</param>
        /// <param name="parsedLines"></param>
        /// <returns>True, if parsing was successful</returns>
        private bool ExecuteParse(int fileIndex, SourceFileItem sourceItem, string sourceText,
                                  out List <SourceLineBase> parsedLines)
        {
            // --- No lines has been parsed yet
            parsedLines = new List <SourceLineBase>();

            // --- Parse all source code lines
            var inputStream = new AntlrInputStream(sourceText);
            var lexer       = new Z80AsmLexer(inputStream);
            var tokenStream = new CommonTokenStream(lexer);
            var parser      = new Z80AsmParser(tokenStream);
            var context     = parser.compileUnit();
            var visitor     = new Z80AsmVisitor(inputStream);

            visitor.Visit(context);
            var visitedLines = visitor.Compilation;

            // --- Store any tasks defined by the user
            StoreTasks(sourceItem, visitedLines.Lines);

            // --- Collect syntax errors
            foreach (var error in parser.SyntaxErrors)
            {
                ReportError(sourceItem, error);
            }

            // --- Exit if there are any errors
            if (Output.ErrorCount != 0)
            {
                return(false);
            }

            // --- Now, process directives and the .model pragma
            var currentLineIndex = 0;
            var ifdefStack       = new Stack <bool?>();
            var processOps       = true;

            parsedLines = new List <SourceLineBase>();
            var anyProcessed = false;

            // --- Traverse through parsed lines
            while (currentLineIndex < visitedLines.Lines.Count)
            {
                var line = visitedLines.Lines[currentLineIndex];
                switch (line)
                {
                case ZxBasicPragma _:
                {
                    if (anyProcessed)
                    {
                        ReportError(Errors.Z0450, line);
                        break;
                    }

                    _options.UseCaseSensitiveSymbols = true;
                    _options.ProcExplicitLocalsOnly  = true;
                    _options.FlexibleDefPragmas      = true;
                    CurrentModule     = Output = new AssemblerOutput(sourceItem, true);
                    Output.SourceType = "zxbasic";
                    anyProcessed      = true;
                    break;
                }

                case ModelPragma modelPragma:
                    ProcessModelPragma(modelPragma);
                    anyProcessed = true;
                    break;

                case IncludeDirective incDirective:
                {
                    // --- Parse the included file
                    if (ApplyIncludeDirective(incDirective, sourceItem,
                                              out var includedLines))
                    {
                        // --- Add the parse result of the include file to the result
                        parsedLines.AddRange(includedLines);
                        anyProcessed = true;
                    }

                    break;
                }

                case LineDirective lineDirective:
                    // TODO: Process a #line directive
                    break;

                case Directive preProc:
                    ApplyDirective(preProc, ifdefStack, ref processOps);
                    anyProcessed = true;
                    break;

                default:
                {
                    if (processOps)
                    {
                        line.FileIndex       = fileIndex;
                        line.MacroSourceText = sourceText.Substring(line.FirstPosition,
                                                                    line.LastPosition - line.FirstPosition + 1);
                        parsedLines.Add(line);
                        anyProcessed = true;
                    }

                    break;
                }
                }
                currentLineIndex++;
            }

            // --- Check if all #if and #ifdef has a closing #endif tag
            if (ifdefStack.Count > 0 && visitedLines.Lines.Count > 0)
            {
                ReportError(Errors.Z0062, visitedLines.Lines.Last());
            }

            return(Output.ErrorCount == 0);
        }
Beispiel #12
0
        /// <summary>
        /// Gets all the tags that intersect the specified spans.
        /// </summary>
        /// <param name="spans">The spans to visit.</param>
        /// <returns>
        /// A <see cref="T:Microsoft.VisualStudio.Text.Tagging.TagSpan`1" /> for each tag.
        /// </returns>
        public IEnumerable <ITagSpan <Z80AsmTokenTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            foreach (var curSpan in spans)
            {
                var currentLine = curSpan.Start.GetContainingLine();
                var textOfLine  = currentLine.GetText();

                // --- Let's use the Z80 assembly parser to obtain tags
                var inputStream = new AntlrInputStream(textOfLine);
                var lexer       = new Z80AsmLexer(inputStream);
                var tokenStream = new CommonTokenStream(lexer);
                var parser      = new Z80AsmParser(tokenStream);
                var context     = parser.asmline();
                var visitor     = new Z80AsmVisitor();
                visitor.Visit(context);
                if (!(visitor.LastAsmLine is SourceLineBase asmline))
                {
                    continue;
                }

                if (asmline.LabelSpan != null)
                {
                    // --- Retrieve a label
                    yield return(CreateSpan(currentLine, asmline.LabelSpan, Z80AsmTokenType.Label));
                }

                if (asmline.KeywordSpan != null)
                {
                    var type = Z80AsmTokenType.Instruction;
                    if (asmline is PragmaBase)
                    {
                        type = Z80AsmTokenType.Pragma;
                    }
                    else if (asmline is Directive)
                    {
                        type = Z80AsmTokenType.Directive;
                    }

                    // --- Retrieve a pragma/directive/instruction
                    yield return(CreateSpan(currentLine, asmline.KeywordSpan, type));
                }

                if (asmline.CommentSpan != null)
                {
                    // --- Retrieve a comment
                    yield return(CreateSpan(currentLine, asmline.CommentSpan, Z80AsmTokenType.Comment));
                }

                if (asmline.Numbers != null)
                {
                    foreach (var numberSpan in asmline.Numbers)
                    {
                        // --- Retrieve a number
                        yield return(CreateSpan(currentLine, numberSpan, Z80AsmTokenType.Number));
                    }
                }

                if (asmline.Identifiers == null)
                {
                    continue;
                }

                foreach (var idSpan in asmline.Identifiers)
                {
                    // --- Retrieve a number
                    yield return(CreateSpan(currentLine, idSpan, Z80AsmTokenType.Identifier));
                }
            }
        }