微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

antlr 函数体缩进

如何解决antlr 函数体缩进

使用这个 https://github.com/antlr/grammars-v4/tree/master/cpp antlr 语法我正在尝试解析 C++ 代码。我想获得每个函数代码,所以我决定访问 visitFunctionBody,你可以看到下面的代码

#include <iostream>
#include <antlr4-runtime.h>

#include "parser/CPP14Lexer.h"
#include "parser/CPP14BaseVisitor.h"
#include "parser/CPP14Parser.h"
#include "parser/CPP14Visitor.h"


class TREEVisitor : public CPP14BaseVisitor {
    public:
        virtual antlrcpp::Any TREEVisitor::visitFunctionBody(
            CPP14Parser::FunctionBodyContext *ctx) override
        {
            std::cout << ctx->getText() << std::endl;
            return visitChildren(ctx);
        }
};


int main(int argc,char *argv[]) {

    std::ifstream stream;
    stream.open(argv[1]);
    antlr4::ANTLRInputStream input(stream);
    CPP14Lexer lexer(&input);
    antlr4::CommonTokenStream tokens(&lexer);
    CPP14Parser parser(&tokens);
    antlr4::tree::ParseTree *tree = parser.translationunit();

    // Visitor
    auto *visitor = new TREEVisitor();
    visitor->visit(tree);

    return 0;
}

我试图解析这个非常基本的 C++ 代码

void foo()
{
    char buf[10];
    int i = 10;
    int b = i * 2;
    return b * i;
}

我的 antlr 访问者函数输出是示例函数代码,但没有任何换行符和缩进,如下所示,

{charbuf[10];inti=10;intb=i*2;returnb*i;}

如何获取我在源文件中解析的函数的源代码

在我的用例中,我解析了一个大的 C++ 文件,我想将解析结果与实际的源代码相匹配。

谢谢

解决方法

这是一种方式,但还有其他方式。在 CPP14Lexer.g4 中,将“->跳过”更改为“->通道(隐藏)”。然后,在visitFunctionBody()中,将调用“getText()”更改为“myGetText(ctx)”,并定义例程myGetText() *像这样,但对于C++“。这段代码是用Java编写的。

public String myGetText(ParseTree node) {
    if (node.getChildCount() == 0) {
        Token t = ((TerminalNodeImpl)node).getSymbol();
        List<Token> tokensBefore = tokens.getHiddenTokensToLeft(t.getTokenIndex(),Token.HIDDEN_CHANNEL);
        String pre = "";
        if (tokensBefore != null) {
            StringBuilder builder2 = new StringBuilder();
            for (Token token : tokensBefore) {
                CharStream input = token.getInputStream();
                String s = input.getText(Interval.of(token.getStartIndex(),token.getStopIndex()));
                builder2.append(s);
            }
            pre = builder2.toString();
        }
        String s2 = node.getText();
        String ss = pre + s2;
        return ss;
    }
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < node.getChildCount(); i++) {
        String s = myGetText(node.getChild(i));
        builder.append(s);
    }
    return builder.toString();
}

你也可以通过直接查询char流树中叶子节点之间涉及的字符,在不将“skip”改为“HIDDEN”的情况下重构文本。

static void Reconstruct(ParseTree node,Parser parser)
{
    var ct = (ParserRuleContext)node;
    Token ta = ct.getStart();
    Token tb = ct.getStop();
    var input_stream = ta.getInputStream();
    var start = ta.getStartIndex();
    var stop = tb.getStopIndex();
    System.out.println(input_stream.getText(new Interval(start,stop)));
}
,

您只需要保留空白标记(将它们推送到 HIDDEN 频道)。

然后,您将需要在您的 Listener/Visitor 中访问您的 TokenStream。然后,您可以为您的上下文和 getText(interval) 创建间隔。这将包括 HIDDEN 频道上的令牌。

示例:

在您的词法分析器中,将 -> skip 更改为 -> channel(HIDDEN)

Whitespace: [ \t]+ -> channel(HIDDEN);

Newline: ('\r' '\n'? | '\n') -> channel(HIDDEN);

BlockComment: '/*' .*? '*/' -> channel(HIDDEN);

LineComment: '//' ~ [\r\n]* -> channel(HIDDEN);

解析您的输入后,将您的 TokenStream 传递给您的侦听器。

...
  CommonTokenStream tokens = new CommonTokenStream(lexer);
...
  ParseTree tree = parser.translationUnit(); 
...
  CPPListener listener = new CPPListener(tokens); 
  ParseTreeWalker walker = new​ ParseTreeWalker();
  walker.walk(listener,tree);

然后在您的听众中:

class CPPListener extends CPP14ParserBaseListener {
    TokenStream tokenStream;
    
    CPPListener(TokenStream tokenStream) {
        this.tokenStream = tokenStream;
    }

    @Override
    public void exitFunctionDefinition(CPP14Parser.FunctionDefinitionContext ctx) {
        Interval interval = new Interval(
           ctx.start.getTokenIndex(),ctx.stop.getTokenIndex()
        );
        String source = tokenStream.getText(interval);
        System.out.println(source);
    }
}

示例输出:

void foo()
{
    char buf[10];
    int i = 10;
    int b = i * 2;
    return b * i;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。