Antlr4入门学习及实用案例(一)

Antlr4入门学习及实用案例(一)

ANTLR4 (ANother Tool for Language Recognition) 是一个功能强大的解析器生成器,可以用来读取、处理、执行或格式化结构化文本或二进制文件。它被广泛用于构建语言、工具和框架。

工作流程及基础理论

学习 ANTLR4,首先要理解其工作流程和基础理论。

1. ANTLR4 的工作流程

整个流程可以概括为三步:

  1. 定义语法 (Grammar):使用 ANTLR4 的特殊语法(保存在 .g4 文件中)来描述自然语言或数据格式的结构。
  2. 生成代码 (Generate):使用 ANTLR4 工具(一个.jar文件 或 antlr4的maven插件)来处理 .g4 语法文件,它会自动生成一套源代码(支持 Java, Python, C# 等),包括词法分析器、语法分析器、监听器和访问者。
  3. 集成与实现 (Implement):将这些生成的代码集成到项目中,并编写自己定义的代码来 "遍历" ANTLR4生成的语法分析树(Parse Tree),从而实现具体的业务逻辑(如计算、转义、格式化等)。

2. 核心概念详解

语法文件 (.g4 File)
  • 这是 ANTLR 的核心,所有规则都在这里定义。
  • 一个 .g4 文件可以同时包含词法规则和语法规则。
词法分析器 (Lexer)
  • 作用:读取字符流(如:输入的文本),并将其分解成一个个有意义的"单词",这些"单词"被称为 词法单元(Token)。

    例如,对于输入 100 + 200,Lexer 会生成三个 Token:INT(100)PLUS(+)INT(200),空格通常会被丢弃。

  • 规则定义:在 .g4 文件中,词法规则通常以大写字母开头。例如:INT : [0-9]+ ;

语法分析器 (Parser)
  • 作用:接收 Lexer 生成的 Token 流,并根据定义的语法规则来检查这些 Token 的排列顺序是否"合乎语法"。如果合法,它会构建一个树形结构来表示输入的层级关系,这个树就是 语法分析树(Parse Tree)。

    例如,对于 Token 流 INT, PLUS, INT,Parser 会根据规则 expr : INT PLUS INT; 构建一个 expr 节点,该节点下有三个子节点。

  • 规则定义:在 .g4 文件中,语法规则通常以小写字母开头。例如:expr : term ( '+' term )* ;

语法分析树 (Parse Tree)
  • 这是 Parser 工作的结果,是输入文本的结构化表示。树的根节点是语法的起始规则,内部节点是其他语法规则,叶子节点是词法单元(Token)。而自定义的业务逻辑就是通过" 走遍" 这棵树来实现的。
  • 语法分析树的递归逻辑基于 递归下降解析(Recursive Descent Parsing) 实现,其核心是一种 深度优先、左递归优先 的树构建策略。
监听器 (Listener) vs. 访问者 (Visitor)

ANTLR4 提供了两种遍历 Parse Tree 的设计模式,以实现与分析结果进行交互的能力。

监听器 (Listener):
  • 工作方式:由 ANTLR 的 ParseTreeWalker(树遍历器)来驱动。当遍历器进入(enter)或退出(exit)树的某个节点时,会自动调用实现的监听器中对应的方法(如 enterExpression, exitExpression)。
  • 特点:被动式。不需要控制遍历过程,只需要在特定事件发生时做出响应。方法没有返回值。
  • 适用场景:当需要对所有节点执行某些操作,且操作之间没有复杂的返回值依赖时,比如字节码生成、代码格式化。
访问者 (Visitor):
  • 工作方式:由开发者自己控制遍历。需要显式地在实现的方法中调用 visit(child) 来访问子节点。
  • 特点:主动式。可以自由控制遍历的顺序,甚至可以不访问某些子树,方法可以有返回值。
  • 适用场景:当子节点的计算结果是父节点计算的一部分时,比如表达式求值、构建抽象语法树(AST)、编译器。

环境准备及入门使用

1. 环境准备

  1. 安装 Java JDK: ANTLR4 工具及其生成的 Java 代码都需要 Java 环境。请确保已安装 JDK 8 或更高版本。

  2. 下载 ANTLR4 工具:

    • 访问 ANTLR 官网下载页面

    • 下载 antlr-4.x.x-complete.jar 文件(例如 antlr-4.13.1-complete.jar)。

    • 为了方便,可以将其放在所在项目目录下,或者一个固定的位置,并设置一个别名方便在命令行中使用。

    • 命令行别名设置 (可选但推荐):

      • macOS/Linux (.bashrc or .zshrc):

        ini 复制代码
        export CLASSPATH=".:/path/to/your/antlr-4.13.1-complete.jar:$CLASSPATH"
        alias antlr4='java -jar /path/to/your/antlr-4.13.1-complete.jar'
        alias grun='java org.antlr.v4.gui.TestRig'
      • Windows (CMD/PowerShell): 可以创建一个 .bat 文件,或者直接在命令行中使用完整命令。

  3. 项目管理: 创建一个项目文件夹,例如 AntlrCalculator

less 复制代码
   AntlrCalculator/
   ├── antlr-4.13.1-complete.jar
   ├── src/
   │   └── main/
   │       ├── antlr4/  // .g4 文件存放处
   │       └── java/    // .java 文件存放处
   └── pom.xml          // 如果使用 Maven

对于项目管理:更推荐使用 Maven 或 Gradle。这样可以非常方便地管理依赖和自动生成代码。

可在 Maven 的 pom.xml 中添加 antlr4 依赖及其插件:

xml 复制代码
   <dependencies>
       <dependency>
           <groupId>org.antlr</groupId>
           <artifactId>antlr4-runtime</artifactId>
           <version>${antlr.version}</version>
       </dependency>
   </dependencies>
   
   <build>
       <plugins>
           <plugin>
               <groupId>org.antlr</groupId>
               <artifactId>antlr4-maven-plugin</artifactId>
               <version>${antlr.version}</version>
               <executions>
                   <execution>
                       <goals>
                           <goal>antlr4</goal>
                       </goals>
                   </execution>
               </executions>
               <configuration>
                   <visitor>true</visitor>
                   <listener>true</listener>
                   <sourceDirectory>./src/main/resources</sourceDirectory>
               </configuration>
           </plugin>
       </plugins>
   </build>

注:推荐安装 IntelliJ IDEA 的 ANTLR4 插件,可以高亮显示语法,调试语法规则,提供语法树的可视化工具。

2. 定义语法 (.g4)

可知在 Spring AI 框架中采用了基于 ANTLR 的开源库 StringTemplate 作为提示词模板实现的技术方案,使用 ANTLR4 实现文本规则提取十分简便,接下来让我们动手实现一个简单的提示词模板功能。

在项目目录下创建一个名为 PromptTemplate.g4 的文件,并填写以下内容:

ini 复制代码
grammar PromptTemplate; // 语法文件的头部,定义语法名称,必须与文件名一致
​
template: segment+ ; // 起始规则(节点):定义一个模板(template)由一个或多个片段(segment)组成
​
segment: variable | text ; // 片段规则(节点):由变量(variable)、普通文本(text)组成
​
variable: LBRACE ID RBRACE ; // 变量规则(节点):由左花括号、标识符(ID)、右花括号组成
​
text: TEXT_CHUNK+ ; // 文本规则(节点):一个或多个连续的非花括号字符组成
​
LBRACE: '{' ;
​
RBRACE: '}' ;
​
ID: [a-zA-Z_] [a-zA-Z0-9_]* ;
​
TEXT_CHUNK: ~[{}] + ;

通过 IDEA 的 ANTLR4 插件,输入像 "你好,我的名字是{name}。" 这样的短语,可查看 ANTLR 创建的解析树:

3. 生成代码

打开命令行,进入项目目录,执行以下命令:

shell 复制代码
# -Dlanguage=Java 是可选的,因为java是默认生成语言
# -o <dir> 可以指定输出目录,默认生成在当前目录
java -jar antlr-4.13.1-complete.jar PromptTemplate.g4

执行后,目录下就会生成了一堆 .java 文件和 .tokens 文件(xxx为语法文件的文件名):

  • xxxLexer.java:词法分析器
  • xxxParser.java:语法分析器
  • xxxListener.java:监听器接口
  • xxxBaseListener.java:监听器的空实现,方便继承重写方法
  • xxxVisitor.java:访问者接口
  • xxxBaseVisitor.java:访问者的空实现,方便继承重写方法

如果是 maven 项目,建议使用 antlr4 的maven插件,当构建项目时(例如运行 mvn clean install 或 直接执行 antlr4:antlr4 插件的goals),ANTLR4 插件会自动在 target/generated-sources/antlr4 目录下生成对应的解析文件。

4. 编写代码遍历语法树(使用 Visitor)

Visitor 模式是开发时大多数的选择,因为这里我们需要从子表达式匹配出结果,然后返回给父表达式使用。

  1. 创建一个名为 PromptTemplateEvalVisitor.java 的文件,这个类将继承 PromptTemplateBaseVisitor 并重写我们关心的方法。
typescript 复制代码
public class PromptTemplateEvalVisitor extends PromptTemplateBaseVisitor<String> {
​
    private final Map<String, Object> context; // 提示词模板的上下文数据存储
​
    public PromptTemplateEvalVisitor(Map<String, Object> context) {
        this.context = context;
    }
​
    @Override
    public String visitTemplate(PromptTemplateParser.TemplateContext ctx) {
        StringBuilder sb = new StringBuilder();
        for (org.antlr.v4.runtime.tree.ParseTree child : ctx.children) {
            sb.append(visit(child));  // 递归处理子节点并将结果拼接到字符串
        }
        return sb.toString();
    }
​
    @Override
    public String visitText(PromptTemplateParser.TextContext ctx) {
        return ctx.getText(); // 文本节点直接返回其原始字符串
    }
​
    @Override
    public String visitVariable(PromptTemplateParser.VariableContext ctx) {
        String varName = ctx.ID().getText(); // 从匹配到的标识符(ID)中提取变量名
        Object value = context.get(varName); // 从上下文中获取此变量名的值
        return value != null ? value.toString() : ""; // 变量节点值存在则转换字符串直接返回
    }
}
  1. 编写测试类 PromptTemplateEvalVisitorTest.java 来验证提示词模板功能的流程准确性。
ini 复制代码
@Test
public void testPromptTemplateEval() {
    String template = "Go go go {word_a} 黑咖啡{word_b}有多浓 我只要汽水的{word_c}";
​
    CharStream input = CharStreams.fromString(template);            //  CharStream流     ↓
    PromptTemplateLexer lexer = new PromptTemplateLexer(input);      //  Lexer词法分析器  ↓
    TokenStream tokens = new CommonTokenStream(lexer);              //  Token流          ↓
    PromptTemplateParser parser = new PromptTemplateParser(tokens);  //  Parser语法分析器  ↓
​
    ParseTree tree = parser.template();                            //  从template起始规则开始分析,生成语法分析树
​
    Map<String, Object> context = new HashMap<>();
    context.put("word_a", "出发喽~");
    context.put("word_b", "品味");
    context.put("word_c", "轻松~!");
​
    PromptTemplateEvalVisitor renderer = new PromptTemplateEvalVisitor(context);
    String result = renderer.visit(tree);                         //  遍历语法树,执行自定义的业务逻辑
​
    System.out.println(result);
    assert "Go go go 出发喽~ 黑咖啡品味有多浓 我只要汽水的轻松~!".equals(result);
}

测试验证成功,我们已经成功构建了一个基于 ANTLR4 的简单提示词模板实现:

小总结

我们在这篇文章中了解到 ANTLR4 的基础流程概念及其入门使用方法,并通过一个简单的提示词模板案例,逐步展示了如何使用 ANTLR 解析语法的完整过程。

由于文章篇幅限制,让我们在下一篇文章中使用一些实用的语法特性,并实现其他更通用的语法案例,进一步了解和学习 ANTLR4,帮助我们能够处理更复杂的语言解析任务,探索 ANTLR4 的更多可能性。


Interpreter 1 - Google 文档

简介 - ANTLR 4 简明教程 - 开发文档 - 文江博客

Antlr4系列(一):语法分析器学习 - 知乎

antlr4/doc/parser-rules.md at master · antlr/antlr4 · GitHub

文章案例项目代码:antlr4-simple-demo

相关推荐
微学AI4 小时前
时序数据库选型指南:工业大数据场景下基于Apache IoTDB技术价值与实践路径
大数据·apache·时序数据库
lingling0097 小时前
颐顿机电携手观远BI数据:以数据驱动决策,领跑先进制造智能化升级
大数据·人工智能·制造
b***25117 小时前
电池自动生产线:科技赋能下的高效制造新范式
大数据·人工智能
哈哈很哈哈10 小时前
Hadoop JMX 配置的完整文档
大数据·hadoop·分布式
Dragon online11 小时前
数据仓库深度探索系列:架构选择与体系构建
大数据·数据仓库·分布式·架构·spark·大数据架构·数仓架构
数据要素X12 小时前
【数据架构08】数字化转型架构篇
大数据·数据库·数据仓库·架构·数据库架构
黄雪超13 小时前
Kafka——关于主题管理
大数据·分布式·kafka
阿里云大数据AI技术13 小时前
【跨国数仓迁移最佳实践4】MaxCompute 企业级能力升级:跨域访问控制与数据安全特性增强
大数据·人工智能·云计算
天天讯通14 小时前
机器人系统对接线索平台好处
大数据·数据库·人工智能·机器人·语音识别
2501_9248776215 小时前
智慧零售商品识别准确率↑32%:陌讯多模态融合算法实战解析
大数据·算法·目标检测·计算机视觉·视觉检测·边缘计算