使用Antlr解析代码后如何检测循环块?

如何解决使用Antlr解析代码后如何检测循环块?

我正在与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语法生成的文件中具有此值。

Tokens.tokens-> for = 45。

Tokens.lexer.tokens-> for = 45

TokensParser.java-> Rule_forBlock = 39; Rule_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检测源代码中的循环并区分外部循环和内部循环?

解决方法

您没有提供足够的代码/语法来重现您所描述的内容。因此,我将给您演示如何使用the C++ grammar in the ANTLR repository解决该问题的示例。

我只更改了1条规则。代替:

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

我在其中添加了labels

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.

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

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-