在 .NET 应用中使用 ANTLR

什么是 ANTLR ?

ANTLR 是功能强大的解析器生成器,用于读取,处理,执行或翻译结构化文本或二进制文件。它被广泛用于构建语言,工具和框架。ANTLR从语法中生成一个解析器,该解析器可以构建和遍历解析树。

ANTLR 语法库

ANTLR 为常见的语言构建了语法文件, 可以直接下载使用 https://github.com/antlr/grammars-v4 。 如果需要在程序中处理常用的语言, 可以先来这里找一下。

如何在 .NET 中使用 ANTLR ?

ANTLR 被广泛应用与大数据分析、 人工智能等领域的语法分析, 网上的相关资料确实非常多, 但是 .NET 相关的资料却很少, 有的也是年代久远, 几乎没有什么参考价值。

经过一番摸索, 终于找到了在 .NET 中使用 ANTLR 的正确方法, 于是记录下来。

新建 .NET 命令行项目

  1. 首先, 当然是新建一个 .NET 项目, 命令如下:

    dotnet new console AntlrDemo
    
  2. 添加 NuGet 包 Antlr4.Runtime.Standard , 目前的版本是 4.9.2 , 这是一个 .NET Standard 2.0 标准类库, 可以在大多数 .NET 环境中使用:

    dotnet add package Antlr4.Runtime.Standard --version 4.9.2
    

生成 C# 代码

  1. 下载 ANTLR 工具包

    访问 ANTLR 的 下载 页面, 下载完整的 ANTLR jar 包, 需要用这个来生成 C# 源代码。

    由于要运行 jar 文件, 所以还得装一个 jre , 不过运行时不需要 jre 。

  2. 根据语法文件生成对应的 C# 代码

    以 ANTLR 提供的 SQLite 语法文件为例, 生成代码的命令为:

    java -jar .tools/antlr-4.9.2-complete.jar \
      -Dlanguage=CSharp \ # 指定生成的语言为 C#
      -package AntlrDemo.Generated \ # 指定输出代码的命名空间
      -o ./src/AntlrDemo/Generated \ # 指定输出的目录
      SQLiteParser.g4 SQLiteLexer.g4 # 提供语法文件
    
  3. 编译一下, 确认没有错误

    dotnet build
    

使用生成的 C# 代码

要使用生成的 C# 代码, 根据 ANTLR 针对的 C# 说明 , 对应的代码如下:

var sql = "select * from t where id < 10";
ICharStream charStream = CharStreams.fromString(sql);
ITokenSource lexer = new SQLiteLexer(charStream);
ITokenStream stream = new CommonTokenStream(lexer);
SQLiteParser parser = new SQLiteParser(stream);
parser.BuildParseTree = true;
IParseTree tree = parser.parse();

上面的代码创建了解释器 (parser) 和 对应的语法树 (tree) 两个对象, 有了它们之后, 可以做类似下面的操作:

  • 判断是否存在语法错误

    如果要简单判断 sql 的内容有没有语法错误的话, 可以读取 parserNumberOfSyntaxErrors 属性进行判断

    if (parser.NumberOfSyntaxErrors > 0) {
        throw new Exception("Invalid SQL!");
    }
    
  • 检查语法树的每一个节点

    比如 where 后面的每一个表达式是否合法, 不能出现 1=1 之类的表达式, 则需要使用 ParseTreeWalker 来循环整个语法树。

    先创建一个自定义的监听器, 代码如下:

    public class SqliteParserListener : SQLiteParserBaseListener {
    
        // 只监听退出表达式的方法, 根据提供的语法文件, 还会有很多其它的方法可以重写。
        public override void ExitExpr(
            [NotNull] SQLiteParser.ExprContext context
        ) {
            var text = context.GetText();
            Console.WriteLine(text);
        }
    }
    

    调用监听器 SqliteParserListener 并循环整个语法树的代码为:

    var listener = new SqliteParserListener();
    ParseTreeWalker.Default.Walk(listener, tree);
    

ANTLR 使用小结

ANTLR 是一个通用的解析器生成器, 只要能够构建语法文件, 就能生成对应的解析器, 生成对应的语法树进行分析。 不仅提供了大量的语法文件, 也可以根据语法创建自定义的语法文件, 各家的 IDE 工具 (JetBrains, Visual Studio, Visual Studio Code, Eclipse 等)也都对其语法文件提供了可视化支持, 如果需要在代码中动态分析解释特定的语法, ANTLR 可以说是首选工具。

本博客基于 Tabler CSS 框架, 采用 Jekyll 模板引擎, 使用 Markdown 语法编写。

博客源代码及文章内容采用 AS-IS 协议发布,转载时请 AS-IS 。