ANTLR4性能问题
对ANTL4解析的性能进行了一些讨论,例如:ANTLR4性能问题,antlr4,Antlr4,对ANTL4解析的性能进行了一些讨论,例如: 还有一个公开的bug报告: 这就需要使用两阶段策略来提高ANTLR4的性能。为此,首先在SLL模式下调用解析器,只有在出现故障时才使用较慢的LL模式 这对于小型语法非常有效,如994版中使用的语法: grammar expr; expr: ID | 'not' expr | expr 'and' expr | expr 'or' expr | expr 'between' expr 'and' expr
grammar expr;
expr: ID
| 'not' expr
| expr 'and' expr
| expr 'or' expr
| expr 'between' expr 'and' expr
;
ID: [a-zA-Z_][a-zA-Z_0-9]*;
WS: [ \t\n\r\f]+ -> skip;
ERROR: .;
但如果语法变得稍微复杂和模糊:
/**
* see https://github.com/antlr/antlr4/issues/994
*/
grammar numexpr;
numexpr: if_statement EOF;
if_statement:
if_part ( else_part ) ? 'endif';
if_part:
'if' expr statement_list|
'if' expr;
else_part:
'else' statement_list |
'else';
statement_list:
statement +;
statement: if_statement;
expr: ID
| VALUE
| 'not' expr
| expr '=' expr
| expr 'and' expr
| expr 'or' expr
| expr 'between' expr 'and' expr
;
VALUE: [0-9]+;
ID: [a-zA-Z_][a-zA-Z_0-9]*;
WS: [ \t\n\r\f]+ -> skip;
ERROR: .;
使用两阶段策略不再有效。
计时结果是:
2 27 msecs 0,2
3 95 msecs 3,5
4 99 msecs 1,0
5 64 msecs 0,6
6 87 msecs 1,4
7 181 msecs 2,1
8 350 msecs 1,9
9 822 msecs 2,3
10 2912 msecs 3,5
11 7134 msecs 2,4
12 21420 msecs 3,0
ratio: 2,01
从输入开始添加每个“and valuex=x”表达式部分所需的时间是原来的两倍多
if Value=0 and not Value0=0 and not Value1=1 endif.
需要对语法进行一些修改,使其适合SLL
这将如何实现?
if(mode.equals(PredictionMode.LL\u EXACT\u AMBIG\u DETECTION)){
parserHolder.parser.addErrorListener(新的DiagnosticeErrorListener());
}
并将doTestParser行更改为:
doTestParser(parserHolder,PredictionMode.LL_-EXACT\u-AMBIG\u-DETECTION,PredictionMode.LL);
我也没有得到任何歧义行,但只得到:
if Value=0 and not Value0=0 and not Value1=1 endif
line 1:20 reportAttemptingFullContext d=6 (expr), input='andnotValue0'
line 1:12 reportContextSensitivity d=6 (expr), input='and'
line 1:37 reportAttemptingFullContext d=6 (expr), input='andnotValue1'
line 1:29 reportContextSensitivity d=6 (expr), input='and'
请在下面找到显示问题的JUnit测试。它由两个类组成——一个抽象基类和一个测试类,该类显示了
- 及
package com.bitplan.ruleparser;
导入java.io.IOException;
导入org.antlr.v4.runtime.antlInputStream;
导入org.antlr.v4.runtime.CommonTokenStream;
导入org.antlr.v4.runtime.Lexer;
导入org.antlr.v4.runtime.ParserRuleContext;
导入org.junit.Test;
导入com.bitplan.expr.exprLexer;
导入com.bitplan.expr.exprParser;
导入com.bitplan.numexpr.numexprLexer;
导入com.bitplan.numexpr.numexprParser;
/**
*测试问题994的性能
*
*@author wf
*
*/
公共类TestIssue994扩展了TestTwoPhaseParser{
公共静态类ExprParserHolderFactory扩展ParserHolderFactory{
@凌驾
ParserHolder getParserHolder(int索引)引发异常{
返回新的ExprParserHolder(索引);
}
}
/**
*
*@author wf
*
*/
公共静态类ExprParserHolder扩展了ParserHolder{
public ExprParserHolder(int索引)引发IOException{
超级(指数);
}
私人快递公司;
@凌驾
受保护的org.antlr.v4.runtime.Parser getParser(CommonTokenStream令牌){
mParser=新的exprParser(令牌);
返回mParser;
}
@凌驾
受保护的Lexer getLexer(AntlInputStream-in){
返回新的exprLexer(in);
}
@凌驾
受保护的ParserRuleContext parse(){
返回mParser.expr();
}
@凌驾
受保护的字符串getInput(int索引){
字符串ANDCLASSION=“非X0”;
对于(int i=0;i您应该按描述拆分左递归expr
非递归或基本递归规则。这是@kvantt建议拆分后语法的处理方式
/**
* see https://github.com/antlr/antlr4/issues/994
*/
grammar primrecexpr;
primrecexpr: if_statement EOF;
if_statement:
if_part ( else_part ) ? 'endif';
if_part:
'if' expr statement_list|
'if' expr;
else_part:
'else' statement_list |
'else';
statement_list:
statement +;
statement: if_statement;
expr:
notexpr
| expr 'and' expr
| expr 'or' expr
;
notexpr:
'not' notexpr
| equalexpr;
equalexpr:
atomexpr |
equalexpr '=' equalexpr
;
atomexpr:
ID
| VALUE;
VALUE: [0-9]+;
ID: [a-zA-Z_][a-zA-Z_0-9]*;
WS: [ \t\n\r\f]+ -> skip;
ERROR: .;
使用修改后的Grammarth查看计时结果会很好。结果是对性能没有任何可测量的影响,这取决于表达式的长度。基本上,解析时间总是相同的,并且取决于计算机的速度。
/**
* see https://github.com/antlr/antlr4/issues/994
*/
grammar primrecexpr;
primrecexpr: if_statement EOF;
if_statement:
if_part ( else_part ) ? 'endif';
if_part:
'if' expr statement_list|
'if' expr;
else_part:
'else' statement_list |
'else';
statement_list:
statement +;
statement: if_statement;
expr:
notexpr
| expr 'and' expr
| expr 'or' expr
;
notexpr:
'not' notexpr
| equalexpr;
equalexpr:
atomexpr |
equalexpr '=' equalexpr
;
atomexpr:
ID
| VALUE;
VALUE: [0-9]+;
ID: [a-zA-Z_][a-zA-Z_0-9]*;
WS: [ \t\n\r\f]+ -> skip;
ERROR: .;