Nano Hash - криптовалюты, майнинг, программирование

Исключения обработки Antlr

Я разработал сложную грамматику с использованием Antlr 3 с использованием дерева AST. ANTLR генерирует лексер и парсер. Проблема в том, что когда пользователь вводит недопустимый синтаксис, например, грамматика ожидает ';'. Пользователь не вводит это, тогда в моей Eclipse IDE я получаю следующее исключение:

 line 1:24 mismatched input '<EOF>' expecting ';'

Как можно обработать это исключение, потому что я пытаюсь перехватить это исключение, но исключение не улавливается. Это вообще исключение? Кажется, я не понимаю, почему это исключение не улавливается. Я попытался это выяснить, однако сайт Antlr, похоже, уже некоторое время не работает.

Я посмотрел на следующее: Обработка исключений ANTLR с помощью $, Java и последовал этому примеру, но когда Lexer генерирует код, добавляя RuntimeException (), я получаю недостижимый код.

Я не уверен что делать.

Когда я пытаюсь получить от парсера количество синтаксических ошибок, он отображает 0.

РЕДАКТИРОВАТЬ:

Я нашел решение, которое работает, взглянув на: ANTLR не выдает ошибок при недопустимом вводе

Однако когда я пытаюсь вернуть сообщение об исключении, оно оказывается пустым. Все ли правильно настроил? См. Образец грамматики:

grammar i;

options {
output=AST;
}

@header {
package com.data;
}

@rulecatch {
    catch(RecognitionException e) {
        throw e;
   }
}

// by having these below it makes no difference
/**@parser::members {
    @Override
    public void reportError(RecognitionException e) {
        throw new RuntimeException("Exception : " + " " + e.getMessage());
    }
}

@lexer::members {
    @Override
    public void reportError(RecognitionException e) {
       throw new RuntimeException("Exception : " + " " + e.getMessage());
    }
}*/

РЕДАКТИРОВАТЬ:

Пожалуйста, посмотрите, что у меня есть на данный момент:

grammar i;

options {
output=AST;
}

@header {
package com.data;
}

@rulecatch {
    // ANTLR does not generate its normal rule try/catch
    catch(RecognitionException e) {
        throw e;
    }
}

@parser::members {
    @Override
    public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
        String hdr = getErrorHeader(e);
        String msg = getErrorMessage(e, tokenNames);
        throw new RuntimeException(hdr + ":" + msg);
    }
}

@lexer::members {
    @Override
    public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
        String hdr = getErrorHeader(e);
        String msg = getErrorMessage(e, tokenNames);
        throw new RuntimeException(hdr + ":" + msg);
    }
}

operatorLogic   : 'AND' | 'OR';
value       : STRING;
query       : (select)*;
select      : 'SELECT'^ functions 'FROM table' filters?';';
operator    : '=' | '!=' | '<' | '>' | '<=' | '>=';
filters : 'WHERE'^ conditions;
members : STRING operator value;
conditions  : (members (operatorLogic members)*);
functions   : '*';
STRING  : ('a'..'z'|'A'..'Z')+;
WS      : (' '|'\t'|'\f'|'\n'|'\r')+ {skip();}; // handle white space between keywords

public class Processor {

public Processor() {

}

/**
 * This method builds the MQL Parser.
 * @param args the args.
 * @return the built IParser.
 */
private IParser buildMQLParser(String query) {
    CharStream cs = new ANTLRStringStream(query);
    // the input needs to be lexed
    ILexer lexer = new ILexer(cs);
          CommonTokenStream tokens = new CommonTokenStream();
    IParser parser = new IParser(tokens);
    tokens.setTokenSource(lexer);
    // use the ASTTreeAdaptor so that the grammar is aware to build tree in AST format
    parser.setTreeAdaptor((TreeAdaptor) new ASTTreeAdaptor().getASTTreeAdaptor());
return parser;
}

/**
 * This method parses the MQL query.
 * @param query the query.
 */
public void parseMQL(String query) {
    IParser parser = buildMQLParser(query);
    CommonTree commonTree = null;
    try {
                     commonTree = (CommonTree) parser.query().getTree();
                    }
    catch(Exception e) {
        System.out.println("Exception :" + " " + e.getMessage());
    }
}
}

public class ASTTreeAdaptor {

public ASTTreeAdaptor() {

}

/**
 * This method is used to create a TreeAdaptor.
 * @return a treeAdaptor.
 */
public Object getASTTreeAdaptor() {
    TreeAdaptor treeAdaptor = new CommonTreeAdaptor() {
        public Object create(Token payload) {
        return new CommonTree(payload);
        }
    };
    return treeAdaptor; 
}
}

Итак, когда я ввожу следующее: SELECT * FROM table

без ';' Я получаю исключение MismatchedTokenException:

catch(Exception e) {
     System.out.println("Exception : " + " " e);
}

Когда я пытаюсь:

e.getMessage();

он возвращает ноль.


Ответы:


1

Вместо этого попробуйте заменить displayRecognitionError:

@parser::members { 
   ...

    @Override    
    public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
        String hdr = getErrorHeader(e);
        String msg = getErrorMessage(e, tokenNames);
        throw new RuntimeException(hdr + ":" + msg);
    }
    ...
}
//same code in @lexer::members

Если вы хотите отслеживать ошибки, а не прекращать работу, вы можете создать интерфейс обработчика для их отслеживания:

@parser::members { 
   ...
    private YourErrorTrackerInterface errorTracker;

    //getter/setter for errorTracker here        

    @Override    
    public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
        String hdr = getErrorHeader(e);
        String msg = getErrorMessage(e, tokenNames);
        if (errorTracker != null){
          errorTracker.addError(e, tokenNames, hdr, msg);
        }
    }
    ...
}
//same code in @lexer::members

Затем средство отслеживания ошибок может решить, создать ли исключение или продолжить.


Приведенный выше код позволяет отслеживать "исправимые" ошибки, ошибки, которые ANTLR может пропустить. По-прежнему существуют сценарии, приводящие к неисправимым ошибкам, например SELECT * FROM table (без окончания ;). В этом случае вам придется перехватывать исключения в parseMQL или где-то еще. (Вы можете попробовать написать свой собственный код восстановления, но я бы не рекомендовал вам это делать.)

Вот модифицированный parseMQL, который показывает два разных типа ошибок синтаксического анализа. Обратите внимание, что я удалил вызов getMessage, потому что не все исключения, производные от RecognitionException, заполняют его.

public void parseMQL(String query) {
    iParser parser = buildMQLParser(query);
    CommonTree commonTree = null;
    try {
        commonTree = (CommonTree) parser.query().getTree();
    } catch (MismatchedTokenException e){
        //not production-quality code, just forming a useful message
        String expected = e.expecting == -1 ? "<EOF>" : iParser.tokenNames[e.expecting];
        String found = e.getUnexpectedType() == -1 ? "<EOF>" : iParser.tokenNames[e.getUnexpectedType()];

        System.out.println("Fatal mismatched token exception: expected " + expected + " but was " + found);   

    } catch (RecognitionException e) {
        System.out.println("Fatal recognition exception " + e.getClass().getName()
                + " : " + e);

    } catch (Exception e) {
        System.out.println("Other exception : " + e.getMessage());
    }
}

Ввод SELECT * FROM table выдает сообщение «Неустранимая ошибка несовпадающего токена: ожидается»; но был ‹EOF› ». Это исключение было создано непосредственно ANTLR.

Вход SELECT FROM table; выдает сообщение «Другое исключение: строка 1: 7: отсутствует '*' в 'FROM table'». Это исключение было создано приведенным выше кодом.

29.11.2012
  • Это тоже не работает. Когда я пытаюсь вернуть сообщение, я, как обычно, получаю null. 30.11.2012
  • Пожалуйста, смотрите редактирование выше с тем, что у меня есть сейчас. Может я здесь что-то не так делаю. Я не хочу отслеживать исключения, а на самом деле их распечатываю. 30.11.2012
  • Не уверен, что это помогает: stackoverflow .com / questions / 4627244 / 30.11.2012
  • @ user1646481 Ошибки печати - это форма их отслеживания. Я обновил ответ, чтобы показать, что не все ошибки можно исправить и что вам придется учитывать их отдельно. 30.11.2012

  • 2

    Если я правильно понимаю, вы хотите исправить синтаксические ошибки вашего языка. Вот как у меня эта настройка в моем проекте.

    /**
     * Adapter need for ANTL to recognize our custom nodes
     * 
     * @author Greg
     */
    public class PhantomTreeAdaptor extends CommonTreeAdaptor{
    
        @Override
        public Object create(Token payload){
            return new ASTNode(payload);
        }
    
        @Override
        public Object dupNode(Object old){
            return (old == null) ? null : ((ASTNode) old).dupNode();
        }
    
        @Override
        public Object errorNode(TokenStream input, Token start, Token stop, RecognitionException e){
            return new ASTErrorNode(input, start, stop, e);
        }
    }
    

    Вот узел ошибки

    /**
     * This is our custom Error node used by the adapter.
     * 
     * @author Greg
     */
    public class ASTErrorNode extends ASTNode {
    
        org.antlr.runtime.tree.CommonErrorNode delegate;
    
        public ASTErrorNode(TokenStream input, Token start, Token stop, RecognitionException e) {
    
            delegate = new CommonErrorNode(input, start, stop, e);
    
        }
    
        public boolean isNil() {
            return delegate.isNil();
        }
    
        public int getType() {
            return delegate.getType();
        }
    
        public String getText() {
            return delegate.getText();
        }
    
        public String toString() {
    
            return delegate.toString();
        }
    
    }
    

    Вот так все это склеивается.

     final PhantomSQLLexer lex = new PhantomSQLLexer(input);
    
            final CommonTokenStream tokens = new CommonTokenStream(lex);
            final PhantomSQLParser g = new PhantomSQLParser(tokens);
            g.setTreeAdaptor(new PhantomTreeAdaptor());
            final start_rule_return r = g.start_rule();
            if (g.getNumberOfSyntaxErrors() == 0) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("tree=" + ((Tree) r.tree).toStringTree());
                    LOGGER.debug("-------------------------------------------");
                }
                final ASTNode root = r.tree;
                exec(root);            
            }
            else {
                LOGGER.debug("Error parsing input");
            }
    

    Мы просто создали наш лексер и парсер, а затем настраиваем наш парсер с пользовательским адаптером дерева (PhantomTreeAdaptor). Оттуда мы можем проверить, есть ли у нас ошибки в нашем пользовательском коде.

    29.11.2012
  • У меня также есть настраиваемый TreeAdaptor, и я могу получать данные из дерева. С моим редактированием, показанным выше, я могу вернуть тип исключения, но не детали сообщения. 29.11.2012
  • Этот ответ, похоже, не решает проблему. Не уверен, что делать, так как я могу получить имя класса Exception, но не могу вернуть детали сообщения. 29.11.2012
  • Если вы посмотрите 'ASTErrorNode', он содержит всю информацию, касающуюся RecognitionException Type / Text / ExceptionType, все это там 29.11.2012
  • Я застряну. Есть ли другой способ сделать это вместо обычного? 29.11.2012
  • Кажется, я этого не понимаю. Что с моим последним редактированием не так? Почему не работает? 29.11.2012
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..