ANTLR4解析树简化

  • 本文关键字:ANTLR4 antlr antlr4
  • 更新时间 :
  • 英文 :


有什么方法可以让ANTLR4自动删除生成的解析树中的冗余节点吗?

更具体地说,我一直在尝试GLSL的语法,由于需要规则转发来自动处理运算符优先级,因此解析树中的"表达式"最终会出现长的线性序列。

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

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

语法的基本结构是一个相当直接的克隆,取自该语言的Khronos规范:

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

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

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

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

然后,我认为您将解析树(又名具体语法树)与AST(抽象语法树)混淆了。AST就像解析树的简化版本,它只保留您所需的内容。例如,使用上面的expr规则,AST不会包含任何圆括号的节点,因为优先级是在树本身中编码的,通常不需要知道给定表达式的一部分是否被圆括号括起来。

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

使用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);
    }

相关内容

  • 没有找到相关文章

最新更新