private class Visitor : JavaBaseVisitor<object>
{
private readonly string _rawText;
private readonly SpannableString _text;
private readonly ISyntaxStyler _styler;
private int _index;
internal Visitor(string text, ISyntaxStyler styler)
{
_rawText = text;
_text = new SpannableString(text);
_styler = styler;
}
public override object VisitAnnotation([NotNull] JavaParser.AnnotationContext context)
{
Advance("@", SyntaxKind.Annotation);
VisitAnnotationName(context.annotationName());
this.VisitChildren(context, 2);
return null;
}
public override object VisitPackageDeclaration([NotNull] JavaParser.PackageDeclarationContext context)
{
int index = 0;
var child = context.GetChild(0);
while (child is JavaParser.AnnotationContext)
{
Visit(child);
child = context.GetChild(++index);
}
Advance("package", SyntaxKind.Keyword);
this.VisitChildren(context, index + 1);
return null;
}
public override object VisitTerminal(ITerminalNode node)
{
Advance(node.Symbol.Text, SyntaxKind.Identifier);
return null;
}
internal SpannableString HighlightText()
{
Visit(CreateTree(_rawText));
return _text;
}
private void Advance(int count, SyntaxKind kind)
{
var span = _styler.GetSpan(kind);
_text.SetSpan(span, _index, _index + count, SpanTypes.InclusiveExclusive);
_index += count;
}
private void Advance(string toSkip, SyntaxKind kind)
{
int count = toSkip.Length;
Debug.Assert(string.Compare(_rawText, _index, toSkip, 0, count) == 0);
Advance(count, kind);
}
private static JavaParser.CompilationUnitContext CreateTree(string text)
{
var inputStream = new AntlrInputStream(text);
var lexer = new JavaLexer(inputStream);
var tokenStream = new CommonTokenStream(lexer);
var parser = new JavaParser(tokenStream);
return parser.compilationUnit();
}
}
需要注意的方法是Advance
和VisitTerminal
。实际上,我依赖于这样一个事实,即每个节点最终都分解为终端,因此如果一个节点没有被另一个重写处理(例如visitannotation
中的@
),那么它的每个终端都将位于visitterminal
中。对visitterminal
的每次调用都会添加到索引字段中,我假定该字段与AST和原始文本同步。也就是说,_index
应该同时表示原始文本中的索引和当前标记的索引。
我最近遇到了一个空白问题。语法规则似乎悄无声息地吃掉了空白,而没有在任何解析器规则中提到它。这会导致空白标记无法通过visitterminal
,从而导致所有内容都不对齐。例如,考虑以下Java代码片段:
package a.b.c.d ;
在处理包
之前,当前令牌的索引与原始文本中的索引相同。但是,当处理时,
_index
没有增加空格,所以它比应该的要晚1。当处理;
时,它将比应该的晚2。然后将获得
A
的颜色,A
将获得下一个的颜色。
,D
将获得的颜色;
等。
是否有一种方法可以在访问者中使用空白标记,这样索引就不会被搞乱?谢了。
你说得对,语法会吃掉空白。但lexer没有。我处理语法高亮显示--因此也处理显式标记--包括空格,如下所示。主要是重写lexer的emit
方法。这是我在这里概述的过程的一部分。
>
一个小类,它允许我记录标记源中的类型、开始和停止长度。
public class TokenExtent
{
public string Name { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public TokenExtent(string name, int start, int stop)
{
Name = name;
Start = start;
Length = stop - start + 1;
}
}
每次解析都会填充的TokenExtents列表。
public static List<TokenExtent> TokenExtents = new List<TokenExtent>();
public class BailLexer : LISBASICLexer
{
public BailLexer(ICharStream input) : base(input) { }
public override IToken Emit()
{
IToken token = base.Emit();
switch (token.Type)
{
case ID :
{
TokenExtent extent = new TokenExtent("ID", token.StartIndex, token.StopIndex);
BasicEnvironment.TokenExtents.Add(extent);
break;
}
case COMMENT :
{
TokenExtent extent = new TokenExtent("COMMENT", token.StartIndex, token.StopIndex);
BasicEnvironment.TokenExtents.Add(extent);
break;
}
case WS:
{
TokenExtent extent = new TokenExtent("WS", token.StartIndex, token.StopIndex);
BasicEnvironment.TokenExtents.Add(extent);
break;
}
private void Highlight()
{
foreach (TokenExtent ext in BasicEnvironment.TokenExtents)
{
switch (ext.Name)
{
case "ID" :
{
etCode2.Select(ext.Start, ext.Length);
etCode2.SelectionColor = Color.Blue;
break;
}
case "COMMENT" :
{
etCode2.Select(ext.Start, ext.Length);
etCode2.SelectionColor = Color.DimGray;
break;
}
case "WS":
{
etCode2.Select(ext.Start, ext.Length);
etCode2.SelectionBackColor = Color.BurlyWood;
break;
}
}
}
}
如果没有引用,会导致解析发生更改吗?
现在我得到了:错误。 我知道我的输入被AND和TERM lexer规则匹配,但我希望能够指定TERM是除与AND规则匹配的内容之外的任何内容。
ANTLR语法中解析器和词法分析器规则的调用顺序是什么?例如,在以下语法中,输入 223 始终标识为APLHANUMERIC而不是数字
我是ANTLR4的新手,我试图解析此输入 在这个输入中,A应该是一个函数调用,而B应该是一个名为B的变量。但我在lexer中有一个跳过空格的规则。 如何为此输入编写解析器规则,但保留跳过空格的规则 提前感谢
CloudGate解析规则可以直接导入使用,不需要任何额外的操作,非常方便! 规则列表 规则名称 下载地址 Surge https://async.be/Rule/Basic/Hosts Shadowrocket https://async.be/Rule/Basic/Hosts 解析规则 简要概述:通过实时同步Hosts信息源达到自动更新,同时使用解析模板进行生成。 无需任何其他操作,导入即可使
template.defaults.rules art-template 可以自定义模板解析规则,默认配置了原始语法与标准语法。 修改界定符 // 原始语法的界定符规则 template.defaults.rules[0].test = /<%(#?)((?:==|=#|[=-])?)[ \t]*([\w\W]*?)[ \t]*(-?)%>/; // 标准语法的界定符规则 template.def