我为antlr4定义了以下简单的左递归表达式语法:
grammar BugExample;
// Rule Definitions
value: expression EOF ;
real:
'-'? CONSTANT #constantReal |
FLOAT #variableReal
;
variable: IDENTIFIER ;
expression: // Precedence (highest to lowest)
real #realExpression |
variable #variableExpression |
// expression '!' #factorialExpression |
'-' expression #inversionExpression
;
// Token Definitions
FRACTION: '.' ('0'..'9')* '1'..'9' ;
CONSTANT: 'e' | 'pi' ;
FLOAT: INTEGER FRACTION? ('e' INTEGER)? ;
IDENTIFIER: ('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'0'..'9')* ;
SPACE: (' '|'\t'|'\r'|'\n')+ -> channel(HIDDEN) ;
fragment
NATURAL: '1'..'9' ('0'..'9')* ;
fragment
INTEGER: '0' | '-'? NATURAL ;
注意表达式类型中注释掉的因子表达式。另请注意,FLOAT令牌的定义允许使用负值,因此负实数表达式应优先于反转表达式。随着阶乘表达式被注释掉,生成的JS解析器确实将负常量'-e'正确地解析为真实表达式。但是,如果我们取消对factorial表达式的注释并重新生成解析器,则'-e'会突然被解析为反转表达式。以下是显示它的测试代码:
'use strict';
var language = require('../BugExample');
var testCase = require('nodeunit').testCase;
module.exports = testCase({
'Test Parser': function(test) {
var testValues = ['5.27e-15', '-5.3e22','e', '-e', 'expo', '-expo'];
var expectedResults = [
'RealExpressionContext', // positive real number
'RealExpressionContext', // negative real number
'RealExpressionContext', // positive real constant
'RealExpressionContext', // positive real constant
'VariableExpressionContext', // variable value
'InversionExpressionContext' // negative variable value
];
test.expect(testValues.length);
for (var i = 0; i < testValues.length; i++) {
var value = testValues[i];
console.log('\nTesting: ' + value);
var expression = language.parseValue(value).getChild(0);
test.strictEqual(expression.constructor.name, expectedResults[i]);
}
test.done();
}
});
事实证明,添加任何左递归子规则类型列在“权威Antlr 4参考”中,以表达式为例“二进制”,“三元”和“一元后缀”表达式将导致此问题。我只是为生成的JS解析器验证了这一点。当我查看生成的解析器代码时,看起来表达式()函数中的大小写块的顺序在问题发生时随机化,而当向量表达式被注释掉时,它们按优先顺序排列。不确定这是不是原因,代码太复杂了我无法理解; - )
我在GitHub中放置了显示此示例的JavaScript项目: https://github.com/derknorton/antlr4-bug-example
要测试它,请执行以下操作:
git clone https://github.com/derknorton/antlr4-bug-example
cd antlr4-bug-example
npm install
grunt generate build
# it should work correctly
# then edit test/TestBugExample.js to remove commented factorial expression
grunt generate build
# it should now show the problem
希望我已经为antlr4专家提供了足够的细节来确定问题。任何帮助将不胜感激。
答案 0 :(得分:0)
这个问题结果与早期版本的antlr 4解析器生成器有关。我的Grunt.js文件使用的grunt-antlr4
任务尚未更新,无法使用最新版本的antlr4。它使用的是4.5.1版。在该版本之后,问题似乎已得到解决。有关此实现的完整详细信息,请参见此处:https://github.com/antlr/antlr4/issues/2201