ANTLR4 DefaultErrorStrategy无法注入丢失的令牌

时间:2015-04-29 05:06:31

标签: antlr4

我正在尝试在TestRig中运行以下语法:

grammar COBOLfragment;

// hidden tokens
WS : [ ]+ -> channel(HIDDEN);
NL : '\n' -> channel(HIDDEN);

// keywords
PERIOD : '.';

DIVISION : 'DIVISION';
SECTION : 'SECTION';

DATA : 'DATA';
WORKING_STORAGE : 'WORKING-STORAGE';

FILE : 'FILE';

FD : 'FD';

EXTERNAL : 'EXTERNAL';
GLOBAL : 'GLOBAL';

BLOCK : 'BLOCK';
CONTAINS : 'CONTAINS';
CHARACTERS : 'CHARACTERS';

// data
INTEGER : [0-9]+;
ID : [A-Z][A-Z0-9]*;

dataDivision :
    DATA DIVISION PERIOD
    fileSection?
    workingStorageSection?
;

fileSection :
    FILE SECTION PERIOD
    fileDescription*
;

fileDescription :
    FD fileName=ID
//    (IS? GLOBAL)?          // 1. IS GLOBAL clause
//    (IS? EXTERNAL)?        // 2. IS EXTERNAL clause
    blockClause?
    PERIOD
;

blockClause :
    BLOCK CONTAINS? blockSize=INTEGER CHARACTERS
;

workingStorageSection :
    WORKING_STORAGE SECTION PERIOD
;

使用以下输入:

DATA DIVISION.
FILE SECTION.
FD FD01
WORKING-STORAGE SECTION.

显然,第三行输入(“FD FD01”)缺少PERIOD规则中要求的终结符fileDescription

DefaultErrorStrategy正确地确认了这一点并让人联想到遗失的标记:

parse tree with missing token correcly injected

在stderr上显示正确的报告:line 4:0 missing '.' at 'WORKING-STORAGE'

但如果已注释掉的片段被启用(即,条件'IS EXTERNAL'和'IS GLOBAL'再次被带入语法中),则单个令牌插入失败:

parse tree missing the missing token

在stderr上显示误导性报告:line 4:0 no viable alternative at input 'WORKING-STORAGE'

如何启用完整语法(使用IS EXTERNAL和IS GLOBAL子句)保留纠正丢失的PERIOD的能力?

附注1:如果我启用IS EXTERNAL或IS GLOBAL,但不启用两个子句,那么DefaultErrorStrategy可以正常工作并注入丢失的令牌。

附注2:为两个子句启用的语法生成的代码具有以下额外代码(与仅启用其中一个语法的语法相比):

public final FileDescriptionContext fileDescription() ... {
    ...
    try {
        ...
        switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) {
        case 1:
            {
            setState(31);
            _la = _input.LA(1);
            if (_la==IS) {
                {
                setState(30); match(IS);
                }
            }

            setState(33); match(GLOBAL);
            }
            break;
        }
        ...
    }
    catch (RecognitionException re) {
        ...

adaptivePredict()调用是罪魁祸首,因为它在解析器有机会no viable alternative at input 'WORKING-STORAGE'之前抛出match(PERIOD)(在生成的代码中,未粘贴在此处)。

1 个答案:

答案 0 :(得分:0)

我设法解决了为两个IS子句添加新子句:

(这里只是片段改变了)

...
fileDescription :
    FD fileName=ID
    isClauses?
    blockClause?
    PERIOD
;

isClauses :
    IS? GLOBAL (IS? EXTERNAL)?
|   IS? EXTERNAL
;
...

现在DefaultErrorStrategy完成了工作并注入了缺失的PERIOD

为什么不isClauses : (IS? GLOBAL?) (IS? EXTERNAL)?; 好吧,我当然先尝试过。但是得到了一个警告(警告(154):规则'fileDescription'包含一个可选块,其中至少有一个可以匹配空字符串的替代方案)并且没有丢失PERIOD注入。