Tree 识别ANTLR4中文本说明节点深度的树

Tree 识别ANTLR4中文本说明节点深度的树,tree,antlr4,Tree,Antlr4,我试图解析一些描述树的输入文本 为了更好地解释这个问题,我不是从文本开始,而是从预期的结果开始: 此树可以编写为带括号的表达式(例如): 使用ANTLR4很容易识别: grammar ParenthesizedDepthGrammar; WS : (' '|'\n') -> channel(HIDDEN); TEXT : [-A-Za-z0-9]+; root: item*; item: TEXT ('(' item+ ')')? ; 现在的问题是,我的输入将树

我试图解析一些描述树的输入文本

为了更好地解释这个问题,我不是从文本开始,而是从预期的结果开始:

此树可以编写为带括号的表达式(例如):

使用ANTLR4很容易识别:

grammar ParenthesizedDepthGrammar;

WS : (' '|'\n') -> channel(HIDDEN);

TEXT : [-A-Za-z0-9]+;

root: item*;

item:
    TEXT ('(' item+ ')')?
    ;
现在的问题是,我的输入将树描述为括号内的表达式。取而代之的是,每个节点都有一个数字,表示其深度,它隐式地属于最近的前一个深度较浅的节点。像这样:

1 node-0
2 node-00
3 node-000
3 node-001
3 node-002
2 node-01
3 node-010
4 node-0100
3 node-011
2 node-02
1 node-1
2 node-10
我认为以下语法可以正确识别它:

grammar TextualDepthGrammar;

WS : (' '|'\n') -> channel(HIDDEN);

LEVEL : [0-9]+;
TEXT : [-A-Za-z0-9]+;

root: item[0]*;

item[int parentLevel] returns [int level]:
    LEVEL
    { $level = $LEVEL.int; }
    { $level > $parentLevel }?
    TEXT
    item[$level]*
    ;
但事实并非如此

语义谓词
{$level>$parentLevel}?
正确地切断了解析,但是
level
已经被使用,并且祖父母树节点没有机会尝试解析新的子节点

我认为它需要:

  • 将lexer倒带到
    级别“取消使用”;或
  • 项目开始时提前阅读
    级别
    ,如果不比父级深,则进行规则和保释

  • 但是如何解决呢?

    我可以使用
    getCurrentToken()
    查看(readahead)下一个标记来解决这个问题:

    grammar TextualDepthGrammar;
    
    WS : (' '|'\n') -> channel(HIDDEN);
    
    LEVEL : [0-9]+;
    TEXT : [-A-Za-z0-9]+;
    
    root: item*;
    
    item:
        LEVEL
        TEXT
        (
            { Integer.parseInt(getCurrentToken().getText()) > $LEVEL.int }?
            item
        )*
        ;
    
    对于输入:

    1 node-0
    2 node-00
    3 node-000
    3 node-001
    3 node-002
    2 node-01
    3 node-010
    4 node-0100
    3 node-011
    2 node-02
    1 node-1
    2 node-10
    
    它正确地给出了:

    (root 
      (item 1 node-0 
        (item 2 node-00 
          (item 3 node-000) 
          (item 3 node-001) 
          (item 3 node-002)
        ) 
        (item 2 node-01 
          (item 3 node-010 
            (item 4 node-0100)
          ) 
          (item 3 node-011)
        ) 
        (item 2 node-02)
      ) 
      (item 1 node-1 
        (item 2 node-10)
      )
    )
    
    尽管我发现使用
    getCurrentToken()
    有点不太正式。

    如果决定取决于另一个令牌怎么办?


    如果从当前令牌到要做出决定的令牌之间存在可选令牌,该怎么办?

    确保已修复所有语法生成错误和警告,或者确保它们无关紧要。
    TEXT
    规则应给出不完整的范围警告。要在集合中包含文字连字符,它必须是最后一个元素

    TEXT : [A-Za-z0-9-]+;
    
    为了确保解析器考虑所有输入,您需要确定地匹配EOF令牌

    root: item* EOF;
    
    按照Antlr的工作方式,lexer将在计算第一个解析器规则之前使用所有输入。解析器没有简单(或预期)的方法来控制词法分析器的操作


    做您似乎要做的事情的惯用方法是解析并生成整个输入文本的树。在树漫游器中,您可以分析受任意选定约束集约束的树。多个Walker可用于不同的约束集,而无需重新生成树。

    文本lexer规则(开头带有连字符)运行良好。没有错误,没有警告。我只是习惯于用这种方式匹配字符类内部的连字符,因为其他一些实现(vi?grep?sed?我不知道)需要它。作为你的第二个技巧,我认为我最好使用我之前发布的答案(使用
    getCurrentToken()
    ),至少在我遇到类似于我在最后提出的问题的情况之前。对它进行一次解析,然后在树上行走以更正它似乎是在浪费ANTLR4的能力。
    root: item* EOF;