【发布时间】:2017-11-13 01:39:13
【问题描述】:
我正在尝试使用 Xamarin 在 Android 上的 C# 中实现语法突出显示。我正在使用 C# 的 ANTLR v4 library 来实现这一点。我的代码目前是使用this grammar 突出显示Java 的语法,它不会尝试构建解析树并使用访问者模式。相反,我只是将输入转换为令牌列表:
private static IList<IToken> Tokenize(string text)
{
var inputStream = new AntlrInputStream(text);
var lexer = new JavaLexer(inputStream);
var tokenStream = new CommonTokenStream(lexer);
tokenStream.Fill();
return tokenStream.GetTokens();
}
然后我遍历荧光笔中的所有标记,并根据它们的种类为它们分配颜色。
public void HighlightAll(IList<IToken> tokens)
{
int tokenCount = tokens.Count;
for (int i = 0; i < tokenCount; i++)
{
var token = tokens[i];
var kind = GetSyntaxKind(token);
HighlightNext(token, kind);
if (kind == SyntaxKind.Annotation)
{
var nextToken = tokens[++i];
Debug.Assert(token.Text == "@" && nextToken.Type == Identifier);
HighlightNext(nextToken, SyntaxKind.Annotation);
}
}
}
public void HighlightNext(IToken token, SyntaxKind tokenKind)
{
int count = token.Text.Length;
if (token.Type != -1)
{
_text.SetSpan(_styler.GetSpan(tokenKind), _index, _index + count, SpanTypes.InclusiveExclusive);
_index += count;
}
}
最初,我认为这是明智的,因为语法突出显示在很大程度上与上下文无关。但是,我已经发现自己需要在 @ 前面添加特殊情况标识符,因为我希望这些标识符像在 GitHub (example) 上一样作为注释突出显示。 GitHub 提供了在某些情况下为标识符着色的更多示例:here、List 和 ArrayList 是着色的,而 mItems 不是。在这些场景中,我可能需要添加更多代码来突出显示标识符。
我的问题是,在这里检查标记而不是分析树是个好主意吗?一方面,我担心当一个令牌的邻居改变它应该如何突出显示时,我最终可能不得不做很多特殊情况。另一方面,解析将为内存受限的移动设备增加额外的开销,并且当用户在代码编辑器中编辑文本时,实现高效的语法突出显示(例如,不重新标记/解析所有内容)变得更加复杂。我还发现处理所有标记类型而不是解析器规则类型要简单得多,因为您只需在token.Type 上使用switch,而不是覆盖一堆Visit* 方法。
语法高亮的完整代码可供参考,here.
【问题讨论】:
-
你总是需要解析一棵树。复杂的表达式有优先级,顺序很重要。我们都知道 1 + 5 * 6 = 31。然后是 5 + 6 / 4 + 2 = 8.5。
标签: c# .net parsing antlr antlr4