How do I pretty-print productions and line numbers, using ANTLR4?

后端 未结 1 1030
[愿得一人]
[愿得一人] 2021-02-15 16:35

I\'m trying to write a piece of code that will take an ANTLR4 parser and use it to generate ASTs for inputs similar to the ones given by the -tree option on grun (misc.Tes

1条回答
  •  孤城傲影
    2021-02-15 17:33

    The Trees.toStringTree method can be implemented using a ParseTreeListener. The following listener produces exactly the same output as Trees.toStringTree.

    public class TreePrinterListener implements ParseTreeListener {
        private final List ruleNames;
        private final StringBuilder builder = new StringBuilder();
    
        public TreePrinterListener(Parser parser) {
            this.ruleNames = Arrays.asList(parser.getRuleNames());
        }
    
        public TreePrinterListener(List ruleNames) {
            this.ruleNames = ruleNames;
        }
    
        @Override
        public void visitTerminal(TerminalNode node) {
            if (builder.length() > 0) {
                builder.append(' ');
            }
    
            builder.append(Utils.escapeWhitespace(Trees.getNodeText(node, ruleNames), false));
        }
    
        @Override
        public void visitErrorNode(ErrorNode node) {
            if (builder.length() > 0) {
                builder.append(' ');
            }
    
            builder.append(Utils.escapeWhitespace(Trees.getNodeText(node, ruleNames), false));
        }
    
        @Override
        public void enterEveryRule(ParserRuleContext ctx) {
            if (builder.length() > 0) {
                builder.append(' ');
            }
    
            if (ctx.getChildCount() > 0) {
                builder.append('(');
            }
    
            int ruleIndex = ctx.getRuleIndex();
            String ruleName;
            if (ruleIndex >= 0 && ruleIndex < ruleNames.size()) {
                ruleName = ruleNames.get(ruleIndex);
            }
            else {
                ruleName = Integer.toString(ruleIndex);
            }
    
            builder.append(ruleName);
        }
    
        @Override
        public void exitEveryRule(ParserRuleContext ctx) {
            if (ctx.getChildCount() > 0) {
                builder.append(')');
            }
        }
    
        @Override
        public String toString() {
            return builder.toString();
        }
    }
    

    The class can be used as follows:

    List ruleNames = ...;
    ParseTree tree = ...;
    
    TreePrinterListener listener = new TreePrinterListener(ruleNames);
    ParseTreeWalker.DEFAULT.walk(listener, tree);
    String formatted = listener.toString();
    

    The class can be modified to produce the information in your output by updating the exitEveryRule method:

    @Override
    public void exitEveryRule(ParserRuleContext ctx) {
        if (ctx.getChildCount() > 0) {
            Token positionToken = ctx.getStart();
            if (positionToken != null) {
                builder.append(" [line ");
                builder.append(positionToken.getLine());
                builder.append(", offset ");
                builder.append(positionToken.getStartIndex());
                builder.append(':');
                builder.append(positionToken.getStopIndex());
                builder.append("])");
            }
            else {
                builder.append(')');
            }
        }
    }
    

    0 讨论(0)
提交回复
热议问题