Случай, когда ANTLR4 успешно завершает разбор до достижения конца файла из-за ошибки разбора - PullRequest
0 голосов
/ 13 января 2019

Я дал ANTLR4 следующую грамматику синтаксического анализатора и лексера в отдельных файлах (имеется в виду простую грамматику для грамматики BNF)

parser grammar BNFParser;

options {tokenVocab = BNFLexer;}

compileUnit
    :   grammar_rule+
    ;

grammar_rule : NON_TERMINAL COLON (OR? grammar_rule_alternative)* SEMICOLON
           ;

grammar_rule_alternative : (NON_TERMINAL|TERMINAL)+ 
                    ;

и

lexer grammar BNFLexer;

TERMINAL : [A-Z][A-Za-z0-9_]*;
NON_TERMINAL : [a-z][A-Za-z0-9_]*;
OR : '|';
COLON : ':';
SEMICOLON : ';';

WS
  : [ \t\r\n]+ -> skip
 ;

Основная программа

private static void Main(string[] args) {
            StreamReader reader = new StreamReader(args[0]);
            AntlrInputStream stream = new AntlrInputStream(reader);
            BNFLexer lexer = new BNFLexer(stream);
            CommonTokenStream tokens = new CommonTokenStream(lexer);
            BNFParser parser = new BNFParser(tokens);
            IParseTree root = parser.compileUnit();
            Console.WriteLine(root.ToStringTree());
}

Также предоставлен следующий тестовый файл для проверки грамматики

 compileunit : x a
        ;

 x : S b
   ;

 S : compileunit f
  ;

Обратите внимание, из грамматики лексера, что нетерминалы начинаются с строчных букв, а терминалы начинаются с заглавных букв. В данной грамматике есть ошибка. Третье правило использует заглавную букву (S) для определения нетерминала S. Ожидаемое поведение - сообщать об этом как об ошибке. С другой стороны, синтаксический анализ завершается успешно, потребляя первые 2 правила и игнорируя третье для S без сообщения об ошибке. Я также видел сгенерированные файлы, и я заметил следующее

try {
    EnterOuterAlt(_localctx, 1);
    {
    State = 7;
    _errHandler.Sync(this);
    _la = _input.La(1);
    do {
        {
        {
        State = 6; grammar_rule();
        }
        }
        State = 9;
        _errHandler.Sync(this);
        _la = _input.La(1);
    } while ( _la==NON_TERMINAL );
    }
 }
 catch (RecognitionException re) {
     _localctx.exception = re;
     _errHandler.ReportError(this, re);
     _errHandler.Recover(this, re);
 }

Приведенный выше код показывает, что синтаксический анализатор ожидает нетерминальный символ в начале grammar_rule, чего я и ожидаю. Однако что происходит, когда это не так? Еще одна странная проблема заключается в том, что объект CommonTokenStream, который содержит токены, распознаваемые лексером, содержит только токены до конца второго правила, но не токены третьего правила (S). Это правильное поведение?

1 Ответ

0 голосов
/ 14 января 2019

Добавьте токен EOF к основному правилу (compileUnit). Это заставит парсер использовать весь ввод до EOF и сообщать об ошибке, если она не полностью совпадает.

...