java - Antlr4 - 如何在解析器花费太长时间时停止解析器

标签 java antlr4

根据我的语法,当我分析如下条目时:

ZZ9->ZZ9_LINHA  :=  &(_cAlias+"->(CONTAEBTA)"   )+& (_cAlias+"->(REGISTRO)"     )+& (_cAlias+"->(TRANSACAO)"    )+& (_cAlias+"->(REFERENCIA)"   )+;
                    &(_cAlias+"->(REFPAGTO)"    )+& (_cAlias+"->(STATTRANSA)"   )+& (_cAlias+"->(NAOUSADO1)"    )+& (_cAlias+"->(NAOUSADO2)"    )+;
                    &(_cAlias+"->(NUMFATURA)"   )+& (_cAlias+"->(INDDISPUTA)"   )+& (_cAlias+"->(DATFATURAM)"   )+& (_cAlias+"->(DATPARTIDA)"   )+;
                    &(_cAlias+"->(NOMVIAJANT)"  )+& (_cAlias+"->(INIVIAJANT)"   )+& (_cAlias+"->(ROTA)"         )+& (_cAlias+"->(NAOUSADO3)"    )+;
                    &(_cAlias+"->(CENTROCUST)"  )+& (_cAlias+"->(STATUSPGTO)"   )+& (_cAlias+"->(VALORPAGTO)"   )+& (_cAlias+"->(SINALPAGTO)"   )+;
                    &(_cAlias+"->(VALORTRANS)"  )+& (_cAlias+"->(SINALTRANS)"   )+& (_cAlias+"->(NAOUSADO4)"    )+& (_cAlias+"->(NAOUSADO5)"    )+;
                    &(_cAlias+"->(NAOUSADO6)"   )+& (_cAlias+"->(NAOUSADO7)"    )+& (_cAlias+"->(NUMBILHETE)"   )+& (_cAlias+"->(CIAAEREA)"     )+;
                    &(_cAlias+"->(DATEMISSAO)"  )+& (_cAlias+"->(TAXAEMBARQ)"   )+& (_cAlias+"->(SINALTXEMB)"   )+& (_cAlias+"->(VLRBILHET)"    )+;
                    &(_cAlias+"->(SINBILHET)"   )+& (_cAlias+"->(NAOUSADO8)"    )+& (_cAlias+"->(NAOUSADO9)"    )+& (_cAlias+"->(TIPDESPESA)"   )+;
                    &(_cAlias+"->(DATDESPESA)"  )+& (_cAlias+"->(DEPTO)"        )+& (_cAlias+"->(MATRICULA)"    )+& (_cAlias+"->(CODIATA)"      )+;
                    &(_cAlias+"->(NAOUSADOA)"   )+& (_cAlias+"->(REQVIAGEM)"    )+& (_cAlias+"->(NAOUSADOB)"    )+& (_cAlias+"->(CLASSEVOO)"    )

解析器变得越来越慢,并且使用越来越多的内存。

如果工作线程暂停,ANTLR4 堆栈为:

Antlr Stack

我现在无法重构这个语法。所以我正在寻找一种通过超时停止解析器执行的方法。

我已经使用 ExecutorService 和 Future 尝试了以下操作:

public class MyParserIsolateThread implements Callable<ParseTree> {

    public String ppo;
    public MyParserIsolateThread(String ppoInfo)
    {
        this.ppo = ppoInfo;
    }

    @Override
    public ParseTree call() throws Exception {

        NoCaseANTLRStringStream input = new NoCaseANTLRStringStream(this.ppo);
        MyLexer lexer = new MyLexer(input);
        CommonTokenStream token = new CommonTokenStream(lexer);             
        MyParser parser = new MyParser(token);
        AntlrToSonarErrorListener error = new AntlrToSonarErrorListener(null,null,ppo);         
        parser.addErrorListener(error);
        long startTime = System.currentTimeMillis();        
        System.out.println("Starting parsing...");        
        ParseTree tree = parser.program();        
        long estimatedTime = System.currentTimeMillis() - startTime;
        System.out.println("Parse Finished. Elapsed time:" + estimatedTime);        
        return tree;
    }

}


    MyParserIsolateThread threadParser = new MyParserIsolateThread(ppo);
    ExecutorService executorService = Executors.newFixedThreadPool(1);

    Future<ParseTree> result = executorService.submit(threadParser);
    try {
        ParseTree tree = result.get(60, TimeUnit.SECONDS);
        System.out.println("Parser OK ");
    } catch (Exception e) {
        // interrupts if there is any possible error
        System.out.println("too long parsing...");
        result.cancel(true);

    }       
    executorService.shutdownNow();
    try {
        executorService.awaitTermination(1, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("end.");

如果我使用的条目需要超过 60 秒,消息会正确显示,但即​​使使用 shutdownNow,工作线程和池线程也会继续运行。

所以,

有什么办法可以停止 .< startRule > 吗?

我想到了不时调用一些回调来看看我们是否应该停止。

我不想使用线程,并使用 .stop (),因为它已被弃用且不安全。

有什么想法吗?

最佳答案

我确实需要复习语法,但现在做不到。

我按照迈克的想法,得到了预期的行为。

我实现了扩展 ParserATNSimulator 类:

public class ParserATNSimulatorWithTimeOut extends ParserATNSimulator {

    private Instant start = Instant.now();
    public ParserATNSimulatorWithTimeOut(org.antlr.v4.runtime.Parser parser, ATN atn, DFA[] decisionToDFA,
            PredictionContextCache sharedContextCache) {
        super(parser, atn, decisionToDFA, sharedContextCache);
    }
    @Override
    protected void closure(ATNConfig config,
                           ATNConfigSet configs,
                           Set<ATNConfig> closureBusy,
                           boolean collectPredicates,
                           boolean fullCtx,
                           boolean treatEofAsEpsilon)
    {

        Duration timeElapsed = Duration.between(start, Instant.now());
        if (timeElapsed.toMinutes() >= 1 )
        {
            Exception e = new ParseCancellationException("Too long!!!");
            throw new ParseCancellationException(e);

        }
        super.closure(config, configs, closureBusy,collectPredicates,fullCtx,treatEofAsEpsilon);

    }
}

并在 MyParser 中更改它。

public MyParser(TokenStream input) {
        super(input);
        _interp = new ParserATNSimulatorWithTimeOut(this,_ATN,_decisionToDFA,_sharedContextCache);
    }

关于java - Antlr4 - 如何在解析器花费太长时间时停止解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56761502/

相关文章:

java - 在路径中包含 Java 7 的服务器上使用 Play Framework 2.4+

java - 是什么原因导致此错误 "Evaluator.java:6: error: cannot find symbol import org.antlr.v4.runtime.CharStreams;"?

antlr4 - 如何使用Antlr进行语义分析?

java - ANTLR v4 : How to implement deactivation of rule alternatives in listener like embedded semantic predicate in grammar file?

java - 已经安装了德语 Babel。在 Eclipse 中运行的应用程序现在是德语,但导出为 "Eclipse product"仍然是英语

java - 如何将 init() 方法的修改应用到 toString() 中?

java - 无法找到命名参数

java - 我们可以使用java BO sdk获取Json格式的报告内容吗?

java - 在 ANTLR4 中运行时更改与节点关联的规则

compiler-construction - ANTLR4 中的 EOF 行为