使用我的语法,当我分析以下条目时:
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堆栈为:
我现在无法对此语法进行重构。因此,我正在寻找一种通过超时停止执行解析器的方法。
我已经使用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,工作线程和池线程也会继续运行。
所以
有什么方法可以停止。
我想到了不时调用一些回调函数,看看是否应该停止。
我不想使用Thread,而不想使用.stop(),因为它已被弃用且不安全。
有什么主意吗?
答案 0 :(得分:0)
您可以使用与BailOutErrorStrategy
相同的方法:万一发生错误,它会引发异常,而解析机制无法捕获该异常。
在运行解析器之前将其添加到解析器中。覆盖enterEveryRule
方法,并在调用该方法时检查解析器到目前为止运行的时间。如果超时,则抛出您的停止异常,该异常将立即停止解析运行。您可以在代码中捕获此异常,以查看是否已达到超时。
答案 1 :(得分:0)
我肯定需要复习语法,但是我现在不能这样做。
我遵循了Mike的想法,得到了预期的行为。
我实现了对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);
}