2017-01-21 12 views
1

Я пытаюсь создать какой-то инструмент автозаполнения поверх ANTLR4, и у меня есть проблема (возможно, с моим пониманием). Я использую ErrorListener и пытаюсь получить применимые токены от объекта RecognitionException, но этот подход не работает все время.Можно ли с ANTLR4 определить типы токенов, которые применимы в каком-либо положении?

У меня есть грамматики:

grammar WhereClause; 

USER_NAME_COLUMN: 'user_name' ; 
USER_AGE_COLUMN: 'user_age'; 
EQ : '=' ; 
LTH : '<' ; 
GTH : '>' ; 
WS : (' ' | '\t')+ -> skip ; 


stringColumn: USER_NAME_COLUMN ; 
numericColumn: USER_AGE_COLUMN; 
stringRelationalOperator: EQ ; 
numericRelationalOperator: EQ | LTH | GTH ; 
expression: stringColumn stringRelationalOperator stringColumn | numericColumn numericRelationalOperator numericColumn ; 

И какой-то простой тест:

public static void main(String... args) { 
    String data = "user_name = user_name"; 
    for (int i = 1; i <= data.length(); i++) { 
     String input = data.substring(0, i); 
     System.out.println("==========================="); 
     System.out.println(">> " + input + ""); 
     parse(input); 
    } 
} 

private static void parse(String input) { 
    ANTLRInputStream inputStream = new ANTLRInputStream(input); 
    WhereClauseLexer lexer = new WhereClauseLexer(inputStream); 
    CommonTokenStream tokens = new CommonTokenStream(lexer); 
    WhereClauseParser parser = new WhereClauseParser(tokens); 
    lexer.removeErrorListeners(); 
    parser.removeErrorListeners(); 
    parser.addErrorListener(new ANTLRErrorListener() { 
     @Override 
     public void syntaxError(Recognizer<?, ?> recognizer, Object o, int i, int i1, String s, RecognitionException e) { 
      Vocabulary vocabulary = recognizer.getVocabulary(); 
      if (e != null) { 
       e.getExpectedTokens().getIntervals().forEach(interval -> { 
        for (int j = interval.a; j <= interval.b; j++) { 
         System.out.println(vocabulary.getDisplayName(j)); 
        } 
       }); 
      } 
     } 

     @Override 
     public void reportAmbiguity(Parser parser, DFA dfa, int i, int i1, boolean b, BitSet bitSet, ATNConfigSet atnConfigSet) {} 
     @Override 
     public void reportAttemptingFullContext(Parser parser, DFA dfa, int i, int i1, BitSet bitSet, ATNConfigSet atnConfigSet) {} 
     @Override 
     public void reportContextSensitivity(Parser parser, DFA dfa, int i, int i1, int i2, ATNConfigSet atnConfigSet) {} 
    }); 
    parser.expression(); 
} 

И как результат я получаю следовать выход:

=========================== 
>> u 
'user_name' 
'user_age' 
=========================== 
>> us 
'user_name' 
'user_age' 
=========================== 
>> use 
'user_name' 
'user_age' 
=========================== 
>> user 
'user_name' 
'user_age' 
=========================== 
>> user_ 
'user_name' 
'user_age' 
=========================== 
>> user_n 
'user_name' 
'user_age' 
=========================== 
>> user_na 
'user_name' 
'user_age' 
=========================== 
>> user_nam 
'user_name' 
'user_age' 
=========================== 
>> user_name 
'=' 
=========================== 
>> user_name 
'=' 
=========================== 
>> user_name = 
=========================== 
>> user_name = 
=========================== 
>> user_name = u 
=========================== 
>> user_name = us 
=========================== 
>> user_name = use 
=========================== 
>> user_name = user 
=========================== 
>> user_name = user_ 
=========================== 
>> user_name = user_n 
=========================== 
>> user_name = user_na 
=========================== 
>> user_name = user_nam 
=========================== 
>> user_name = user_name 

Это означает, что я дон 't ожидаемый токен для правой части равенства. Кто-нибудь знает причину? Можно ли узнать, какой токен (токены) должен следовать за строкой ввода?

ответ

1

Использование позиции ошибки для завершения кода не будет работать. Что делать, если позиция каретки и позиция ошибки не согласуются? Кроме того, этот простой подход даст вам только ожидаемые ключевые слова, но обычно вы хотите больше (например, все доступные переменные в данной позиции). Итак, вам нужна таблица символов, вам нужен способ определения типа символов, ожидаемых в данной позиции и т. Д.

Использование анализатора для получения кандидатов на выполнение кода не работает. Имейте в виду, что синтаксический анализатор посещает единственный путь, соответствующий вводу, но вам нужны все возможные пути.

В this blog post Я описал возможный подход с использованием ANTLR3, и я работаю над ним для ANTLR4. Другая попытка опубликована Federico Tomassetti. Он по-прежнему возвращает только ключевые слова, но по крайней мере он не использует синтаксический анализатор для этого.

. Обсуждается Terence Parr о предоставлении функции, которая возвращает все следующие наборы: https://github.com/antlr/antlr4/issues/1428