我的antlr 4离开递归表达式而不保留表达式优先顺序

时间:2018-01-10 20:39:18

标签: javascript node.js parsing recursion antlr4

我为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专家提供了足够的细节来确定问题。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

这个问题结果与早期版本的antlr 4解析器生成器有关。我的Grunt.js文件使用的grunt-antlr4任务尚未更新,无法使用最新版本的antlr4。它使用的是4.5.1版。在该版本之后,问题似乎已得到解决。有关此实现的完整详细信息,请参见此处:https://github.com/antlr/antlr4/issues/2201