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