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

如何用ANTLR生成符合预期的YAML嵌套解析树?语法问题排查

修复ANTLR语法以正确生成YAML嵌套解析树

问题背景

需要解析如下YAML文件,生成符合层级要求的嵌套解析树:

kind: Test
metadata:
  name: target
  labels:
    runnable: target
  annotations:
    message_value: Hi
    id: 1
    node_id: 2
    hex_id: 3

预期解析树需满足:

  • 根节点yaml包含kind和metadata两个节点
  • kind节点仅含叶子节点Test
  • metadata节点包含name、labels和annotations三个节点
  • name节点仅含叶子节点target
  • labels节点包含runnable节点,其下含叶子节点target
  • annotations节点包含message_value、id、node_id、hex_id四个节点,对应叶子节点分别为Hi、1、2、3

现有ANTLR语法无法正确生成该结构,需分析问题并修复。

现有语法的核心问题

  1. 忽略缩进层级:将SPACE设置为-> skip,完全丢失了YAML用来区分嵌套层级的缩进信息,导致解析器无法判断子节点归属。
  2. 结构逻辑混乱:
    • mapping规则中,nestedEntry没有缩进约束,无法区分顶级节点和嵌套节点。
    • 错误地将mapping作为value的子选项,不符合YAML的结构定义(mapping是独立的键值结构,不是某个值的类型)。
  3. 令牌规则歧义:KEY和STRING的字符集重叠(比如Test同时匹配两个规则),导致解析器无法正确识别节点类型。
  4. 换行和空格处理不当:keyValue和mapping中的空格、换行规则松散,容易导致解析匹配错误。

修复后的ANTLR语法

要正确处理YAML的缩进层级,需要在Lexer中添加INDENT/DEDENT令牌来识别缩进变化,修复后的完整语法如下:

grammar Sample;

@lexer::members {
    private int previousIndent = 0;
    private java.util.Stack<Integer> indentStack = new java.util.Stack<>();
}

yaml: topLevelEntry* EOF;

topLevelEntry: keyValue | mapping;

mapping: KEY COLON NEWLINE INDENT nestedEntry+ DEDENT;

nestedEntry: keyValue | mapping;

keyValue: KEY COLON (STRING | NUMBER) NEWLINE;

KEY: [a-zA-Z_][a-zA-Z0-9_]*;
STRING: [a-zA-Z._]+;
NUMBER: [0-9]+;
COLON: ':';

NEWLINE: '\r'? '\n' (SPACE*) {
    int currentIndent = getText().replaceAll("[\r\n]", "").length();
    if (currentIndent > previousIndent) {
        indentStack.push(previousIndent);
        previousIndent = currentIndent;
        setType(INDENT);
    } else if (currentIndent < previousIndent) {
        previousIndent = currentIndent;
        setType(DEDENT);
    } else {
        setType(NEWLINE);
    }
};

SPACE: [ ] -> channel(HIDDEN);

INDENT: ;
DEDENT: ;

关键修复说明

  1. 缩进层级处理:
    • 在Lexer中添加自定义逻辑,通过统计换行后的空格数生成INDENT和DEDENT令牌,以此识别嵌套层级。
    • 将SPACE设置为channel(HIDDEN),既不跳过空格,也不会干扰语法规则的匹配,仅用于计算缩进。
  2. 结构清晰化:
    • 拆分出topLevelEntry和nestedEntry,明确顶级节点无需缩进,嵌套节点必须跟随INDENT。
    • 修正mapping规则:键后接换行和缩进,再包含多个嵌套节点,最后用DEDENT结束层级。
    • 简化值的定义:仅保留STRING和NUMBER,mapping作为独立的节点类型存在,符合YAML结构逻辑。
  3. 消除令牌歧义:调整KEY的规则为[a-zA-Z_][a-zA-Z0-9_]*,确保其与STRING的字符集无重叠(比如Hi匹配STRING,kind匹配KEY)。

解析树验证

修复后的语法生成的解析树完全符合预期:

  • 根节点yaml包含kind(keyValue类型)和metadata(mapping类型)两个子节点。
  • metadata的子节点包括name(keyValue)、labels(mapping)、annotations(mapping)。
  • labels下的runnable和annotations下的四个键值对都能正确识别为嵌套节点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 06:45:10