ANTLR: автоматическое восстановление после ошибок не работает - PullRequest
2 голосов
/ 01 декабря 2011

У меня проблема с автоматическим восстановлением ошибок ANTLR v3, которая, похоже, не работает в моей грамматике. Рассмотрим следующую грамматику:

grammar test;

parse   :   define*;

define  :   LPAREN 'define' VARIABLE RPAREN;

// Tokens
LPAREN : '(';
RPAREN : ')';

LETTER  :   ('a'..'z'|'A'..'Z');

VARIABLE : LETTER*;

SPACE : (' ' | '\n' | '\t' | '\r') {$channel = HIDDEN;}; 

когда я вызываю правило разбора со следующим вводом:

(define alpha)
(define beta)

он успешно разбирает оба правила определения. однако, когда я ввожу токен, который не подходит:

(define alpha)
)
(define beta)

он отменяет разбор при первом взгляде на неуместный токен RPAREN. Я думал, что antlr может обрабатывать неуместные токены и пытается вернуться к правилу, но, похоже, это не работает для меня. Что я делаю не так?

спасибо заранее.

1 Ответ

2 голосов
/ 02 декабря 2011

Это потому, что когда вы вызываете правило parse:

parse : define*;

парсер пытается найти как можно больше define правил для ввода:

(define alpha)
)
(define beta)

После успешного совпадения с (define alpha) он видит ), поэтому он больше не может соответствовать правилу define и прекращает его синтаксический анализ. И поскольку ) является действительным токеном в вашей грамматике лексера, вы не видите ни предупреждения, ни ошибки.

Вы должны указать парсеру пройти весь поток токенов , "привязав" правило основного синтаксического анализатора, поместив маркер EOF (конец файла) в конце:

parse : define* EOF;

Если вы снова проанализируете ввод, вы увидите следующую ошибку на вашей консоли:

line 2:0 missing EOF at ')'

EDIT

Тот факт, что define* не восстанавливается, возможно, из-за отсутствия фиксированного количества токенов, что усложняет процесс восстановления. Следующая демонстрация, кажется, подтверждает мое подозрение:

grammar test;

@parser::members {
  public static void main(String[] args) throws Exception {
    String source =  
        "(define alpha) \n" +
        ")              \n" +
        "(define beta)    ";
    testLexer lexer = new testLexer(new ANTLRStringStream(source));
    testParser parser = new testParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}

parse    : define define EOF {System.out.println("parsed >>>" + $text + "<<<");};
define   : LPAREN 'define' VARIABLE RPAREN;
LPAREN   : '(';
RPAREN   : ')';
LETTER   : ('a'..'z'|'A'..'Z');
VARIABLE : LETTER+;
SPACE    : (' ' | '\n' | '\t' | '\r') {$channel = HIDDEN;};

Если вы запускаете класс testParser, на консоль выводится следующее:

line 2:0 extraneous input ')' expecting LPAREN
parsed >>>(define alpha) 
)              
(define beta)    <<<

То есть, предупреждение печатается в System.err, но синтаксический анализ также продолжается при ограничении правила parse двумя define вместо define*.

...