如何在使用antlr解析代码后检测for循环块?

c9qzyr3d  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(508)

我正在使用antlr4,我想解析和分析任何c代码,以检测任何c源代码中的任何循环,对它们进行依赖性分析,我想检测外循环,如果它有内环,我想将其检测为内环,  但是我在源代码中检测不到任何循环。
我所做和尝试的: 
这是我在antlr中用于“for循环”的规则:

forBlock: 'for' '(' (classicFor | forEach) ')' controlStructureBody ;
forExpression: primaryExpression (',' primaryExpression)* ;

我打印出代码中的代币:


# include <iostream>

using namespace std;
int main()
{
    for (int i = 0; i <= 5; i++) {
        for (int j = 0; j <= 5; j++) {
            cout << i << j << " \t";
        }
        cout << "\n";
    }
    return 0;
}

使用此代码 与jave:

public void printToken(String inputFile) throws FileNotFoundException, IOException {
        System.out.println("The tokens of the source code is: \n");
        CharStream inputStream = CharStreams.fromFileName(inputFile);
        TokensLexer tokensLexer = new TokensLexer(inputStream);
        CommonTokenStream tokenStream = new CommonTokenStream(tokensLexer);
        tokenStream.fill();
        for (Token token : tokenStream.getTokens()) {
            System.out.println("<" + token.getText() + "> " + "<" + token.getType() + ">");
        }
    }

它给了我每个for循环的类型:

<for> <45>
<for> <45>

我试过这个代码:

CharStream inputStream = CharStreams.fromFileName(inputFile);
        // lexing the code
        TokensLexer tokensLexer = new TokensLexer(inputStream);
        CommonTokenStream tokenStream = new CommonTokenStream(tokensLexer);
        // parsing the code
        TokensParser tokensParser = new TokensParser(tokenStream);
        tokenStream.fill();
        for (Token token : tokenStream.getTokens()) {
            if (token.getType() == 45)
                System.out.println("loop is found");
        }
}

当我把“45”打印出来 ““找到循环” 两次,当我把号码改成“39”时,它就会打印出来 ““找到循环” 只有一次。  我尝试了“39”,因为我从antlr语法生成的文件中有这个值。
代币。代币-> 对于=45。
tokens.lexer.tokens-> 对于=45
tokensparser.java-> 规则\u forblock=39; 规则\u forexpression=40;
当我尝试添加更多循环时:


# include <iostream>

using namespace std;
int main()
{
    for (int i = 0; i <= 5; i++)
    {
        for (int j = 0; j <= 5; j++) {
            cout << i << j << " \t";
        }
        cout << "\n";
    }
    for (int  i = 0; i < 100; i++)
    {
       cout<<"Test"<<endl;
    }    return 0;
}

使用数字39,仍然只检测一个循环。
有没有一种方法可以使用antlr检测源代码中的循环并区分外循环和内循环?

vc9ivgsu

vc9ivgsu1#

您没有提供足够的代码/语法来重现您所描述的内容。因此,我将演示如何使用antlr存储库中的c++语法来解决这个问题。
我只是稍微改变了一条规则。而不是:

iterationstatement
   : While '(' condition ')' statement
   | Do statement While '(' expression ')' ';'
   | For '(' forinitstatement condition? ';' expression? ')' statement
   | For '(' forrangedeclaration ':' forrangeinitializer ')' statement
   ;

我给它加了一些标签:

iterationstatement
   : While '(' condition ')' statement                                 #WhileStatement
   | Do statement While '(' expression ')' ';'                         #DoWhileStatement
   | For '(' forinitstatement condition? ';' expression? ')' statement #ClassicForStatement
   | For '(' forrangedeclaration ':' forrangeinitializer ')' statement #ForEachStatement
   ;

通过这些更改,以下演示类:

import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

public class Main {

    public static void main(String[] args) throws Exception {

        String source = "#include <iostream>\n" +
                "using namespace std;\n" +
                "int main()\n" +
                "{\n" +
                "    for (int i = 0; i <= 5; i++)\n" +
                "    {\n" +
                "        for (int j = 0; j <= 5; j++) {\n" +
                "            cout << i << j << \" \\t\";\n" +
                "        }\n" +
                "        cout << \"\\n\";\n" +
                "    }\n" +
                "    for (int  i = 0; i < 100; i++)\n" +
                "    {\n" +
                "       cout<<\"Test\"<<endl;\n" +
                "    }    return 0;\n" +
                "}";

        CPP14Lexer lexer = new CPP14Lexer(CharStreams.fromString(source));
        CPP14Parser parser = new CPP14Parser(new CommonTokenStream(lexer));
        ParseTreeWalker.DEFAULT.walk(new ForListener(), parser.translationunit());
    }
}

class ForListener extends CPP14BaseListener {

    private int forLevel = 0;

    @Override
    public void enterClassicForStatement(CPP14Parser.ClassicForStatementContext ctx) {
        this.forLevel++;
        printInfo("classic", ctx);
    }

    @Override
    public void exitClassicForStatement(CPP14Parser.ClassicForStatementContext ctx) {
        this.forLevel--;
    }

    @Override
    public void enterForEachStatement(CPP14Parser.ForEachStatementContext ctx) {
        this.forLevel++;
        printInfo("each", ctx);
    }

    @Override
    public void exitForEachStatement(CPP14Parser.ForEachStatementContext ctx) {
        this.forLevel--;
    }

    private void printInfo(String forType, ParserRuleContext ctx) {
        System.out.printf("%s %s for-statement on line %d.%n",
                this.forLevel == 1 ? "OUTER" : "INNER", forType, ctx.getStart().getLine());
    }
}

将提供以下输出:

OUTER classic for-statement on line 5.
INNER classic for-statement on line 7.
OUTER classic for-statement on line 12.

相关问题