我为 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' 正确解析为真实表达式。 但是,如果我们取消注释阶乘表达式并重新生成解析器,则"-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 解析器验证了这一点。 当我查看生成的解析器代码时,似乎 expression() 函数中大小写块的顺序在问题发生时是随机的,而当阶乘表达式被注释掉时,它们处于优先顺序。 不确定这是否是原因,代码太复杂了,我无法理解;-)
我把展示这个例子的JavaScript项目放在GitHub上: 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专家提供了足够的细节来确定问题。 任何帮助将不胜感激。
这个问题原来是早期版本的antlr 4解析器生成器。 我的 Grunt.js 文件使用的是尚未更新为使用最新版本的 antlr4 的grunt-antlr4
任务。 它使用的是4.5.1版本。 该问题似乎在该版本之后已解决。 此处记录了此实现的完整详细信息:https://github.com/antlr/antlr4/issues/2201