【问题标题】:ANTLR4 parse tree simplificationANTLR4 解析树简化
【发布时间】:2015-03-03 23:12:56
【问题描述】:

有没有办法让 ANTLR4 自动删除生成的解析树中的冗余节点?

更具体地说,我一直在试验 GLSL 的语法,由于自动处理运算符优先级所需的规则转发,您最终会在解析树中得到长的线性“表达式”序列。

大多数生成的树节点只是“前进到下一级优先级”,所以不要提供任何有用的句法信息——你只需要每个序列中的最后一个表达式节点(即规则所在的点)转发停止),或者它成为具有多个子节点的实际树节点(即在源中遇到实际表达式)...

我希望有一种简单的方法可以消除伪中间表达式节点 - 这种类型的结构必须在任何具有运算符优先级的语法中都很常见。

语法的基本结构是从该语言的 Khronos 规范中直接复制而来的:

https://www.khronos.org/registry/gles/specs/3.1/es_spec_3.1.pdf

【问题讨论】:

    标签: antlr antlr4


    【解决方案1】:

    如果您使用这样的语法(基本数学示例),ANTLR v4 能够从处理不同优先级的单个递归规则生成代码:

    expr : '(' expr ')'
         | '-' expr
         | expr ('*'|'/') expr
         | expr ('+'|'-') expr
         | INT
         ;
    

    ANTLR v3 无法做到这一点,基本上要求您为每个优先级编写一个规则。所以我建议你重写你的语法以避免这些样板规则。

    那么,我认为您将parse tree (aka concrete syntax tree)AST (abstract syntax tree) 混淆了。 AST 就像解析树的简化版本,它只保留您需要的内容。例如,使用上面的expr 规则,AST 不会包含任何括号节点,因为优先级是在树本身中编码的,您通常不需要知道给定表达式的一部分是否被括号括起来或不是。

    您的程序应该从解析树构建一个 AST,然后从那里开始。 不要直接处理解析树,即使乍一看似乎很方便,因为该工具会为您生成它们.它很快就会变得很麻烦。构建您自己的树结构 (AST),为手头的任务量身定制。

    【讨论】:

    • 我正在编写一个源到源的翻译器,即旨在删除未使用的变量、未使用的函数等。在可能的情况下,我想保留源格式,所以不想太抽象,但是是的,我同意这种观点。
    • P.S.感谢您对单个递归规则的更新——我认为这将很好地解决问题。 (我仍然试图围绕 ANTLR4 中的变化——与 3 完全不同......)。
    • @Isogen74 是的,它与 v3非常 不同,这是为了更好的恕我直言。无论如何,如果你正在构建一个源到源的翻译器,那么 not 太抽象是完全正确的。您需要解析树来处理此类事情。
    • 这是给你的一个想法(我已经成功使用过):构建一个 AST,并在每个 AST 节点中保留对相关解析树节点的引用。这样你就可以从两者中获得最好的。您可以拥有一个抽象语法树,同时仍然能够将节点与输入中的各个字符相关联。
    • 感谢您的帮助 - 作为一种技术发挥了魅力。
    【解决方案2】:

    使用 Visitor 实现按顺序访问每个节点。通过在访问父节点时向父节点添加节点来构建您自己的树。在访问节点时决定是否将其添加到新树中。例如:

    public T visitExpression(@NotNull AcParser.ExpressionContext ctx) {
            // Expressionable parent = getParent(Expressionable.class, ctx);
            // Class<? extends AcExpression> expClass = AcExpression.class;
            AcExpression obj = null;
            String text = ctx.getText();
    
            //do something with text or children
            for (int i=0; i<ctx.getChildCount(); i++){
                printnl(ctx.getChild(i).getText()+"/");
            }
    
            return visitChildren(ctx);
        }
    

    【讨论】:

    • 谢谢 - 结合 Lucas 的建议(不要偷懒,做一个正确的 AST),这看起来像是要走的路。
    猜你喜欢
    • 2018-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-30
    • 2016-03-18
    相关资源
    最近更新 更多