You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ANTLR4中实现远距离令牌的FIFO式关联?

用ANTLR4实现FIFO顺序的元素配对解析

语法文件设计

首先编写PairGrammar.g4语法,定义输入的结构:左边是逗号分隔的数字列表,中间用冒号分隔,右边是逗号分隔的字母列表:

grammar PairGrammar;

// 顶层规则:匹配完整的配对结构
pairList
    : numberList ':' letterList EOF
    ;

// 数字列表规则
numberList
    : NUMBER (',' NUMBER)*
    ;

// 字母列表规则
letterList
    : LETTER (',' LETTER)*
    ;

// 词法规则
NUMBER : [0-9]+;          // 匹配阿拉伯数字
LETTER : [A-Z]+;          // 匹配大写字母
WS : [ \t\r\n]+ -> skip;  // 忽略空白字符

Java端的配对逻辑实现

ANTLR的pushmode是FILO机制,适合嵌套结构的上下文切换,并不适配这种线性的FIFO配对场景。我们可以通过**解析树监听器(ParseTreeListener)**收集两边的元素,再按顺序关联:

1. 定义配对监听器

实现PairGrammarListener,在遍历语法树时收集数字和字母,完成FIFO配对:

import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.ArrayList;
import java.util.List;

public class PairListener implements PairGrammarListener {
    private final List<String> numbers = new ArrayList<>();
    private final List<String> letters = new ArrayList<>();
    private final List<Pair> pairs = new ArrayList<>();

    // 进入数字列表节点时,收集所有数字
    @Override
    public void enterNumberList(PairGrammarParser.NumberListContext ctx) {
        for (TerminalNode numNode : ctx.NUMBER()) {
            numbers.add(numNode.getText());
        }
    }

    // 进入字母列表节点时,收集字母并完成配对
    @Override
    public void enterLetterList(PairGrammarParser.LetterListContext ctx) {
        for (TerminalNode letterNode : ctx.LETTER()) {
            letters.add(letterNode.getText());
        }
        // 按索引一一配对(FIFO顺序),取两边长度的最小值避免越界
        int matchCount = Math.min(numbers.size(), letters.size());
        for (int i = 0; i < matchCount; i++) {
            pairs.add(new Pair(numbers.get(i), letters.get(i)));
        }
    }

    // 获取最终的配对结果
    public List<Pair> getPairs() {
        return pairs;
    }

    // 定义配对实体类,用于后续创建业务对象
    public static class Pair {
        private final String number;
        private final String letter;

        public Pair(String number, String letter) {
            this.number = number;
            this.letter = letter;
        }

        @Override
        public String toString() {
            return number + "与" + letter + "关联";
        }

        // 可添加getter方法供业务逻辑调用
        public String getNumber() {
            return number;
        }

        public String getLetter() {
            return letter;
        }
    }
}

2. 主程序解析与测试

编写主类来解析输入文本,触发监听器处理逻辑:

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

public class PairParserDemo {
    public static void main(String[] args) {
        String input = "1,2,3:A,B,C";
        // 1. 构建词法分析器
        CharStream charStream = CharStreams.fromString(input);
        PairGrammarLexer lexer = new PairGrammarLexer(charStream);
        // 2. 构建令牌流
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        // 3. 构建语法分析器
        PairGrammarParser parser = new PairGrammarParser(tokens);
        // 4. 解析生成语法树
        ParseTree parseTree = parser.pairList();
        // 5. 遍历语法树,触发监听器逻辑
        ParseTreeWalker walker = new ParseTreeWalker();
        PairListener listener = new PairListener();
        walker.walk(listener, parseTree);
        // 6. 输出配对结果,或用于创建业务对象
        for (PairListener.Pair pair : listener.getPairs()) {
            System.out.println(pair);
            // 示例:用配对结果创建业务对象
            // BusinessObject obj = new BusinessObject(pair.getNumber(), pair.getLetter());
        }
    }
}

运行结果

执行主程序后,会输出:

1与A关联
2与B关联
3与C关联

核心思路说明

  • 无需使用pushmode:模式栈适用于XML标签嵌套这类需要上下文切换的场景,而这里是线性的前后列表关联,通过收集元素后按索引配对即可实现FIFO逻辑。
  • 监听器机制优势:ANTLR的ParseTreeListener允许我们在遍历语法树的特定节点时执行自定义逻辑,完美适配“先收集左边元素,再处理右边元素并关联”的需求。

内容的提问来源于stack exchange,提问作者JavaStudent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:50:07