我的 antlr 4 左递归表达式不保留表达式优先顺序
My antlr 4 left recursive expression not preserving the expression precedence order
我为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();
}
});
事实证明,添加 any 留下了 "Definitive Antlr 4 Reference" 中列出的以表达式开头的递归子规则类型,例如"binary"、"ternary" 和 "unary suffix" 表达式,将导致此问题。我只针对生成的 JS 解析器验证了这一点。当我查看生成的解析器代码时,出现问题时,expression() 函数中 case 块的顺序似乎随机化,而当阶乘表达式被注释掉时,它们按优先顺序排列。不确定是不是这个原因,代码太复杂了,我看不懂 ;-)
我将显示此示例的 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
我为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();
}
});
事实证明,添加 any 留下了 "Definitive Antlr 4 Reference" 中列出的以表达式开头的递归子规则类型,例如"binary"、"ternary" 和 "unary suffix" 表达式,将导致此问题。我只针对生成的 JS 解析器验证了这一点。当我查看生成的解析器代码时,出现问题时,expression() 函数中 case 块的顺序似乎随机化,而当阶乘表达式被注释掉时,它们按优先顺序排列。不确定是不是这个原因,代码太复杂了,我看不懂 ;-)
我将显示此示例的 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