Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> ANTLR. Многострочные комментарии. Обработка в коде 
:(
    Опции темы
PenDaLegi
Дата 14.12.2010, 21:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 14.12.2010
Где: Москва

Репутация: нет
Всего: нет



Всем доброго времени суток!

Используя ANTLR пытаюсь разработать лексер (для начала только лексер) для подсветки синтаксиса. Столкнулся с такой бедой. После генерации лексера почти все работает так как нужно, однако как только ввожу символы многострочного комментария валится экзепшн. Ниже определение комментариев в граммере: 

Код

TOKEN_COMMENT1  : '(*' ( . )* '*)';


Код

TOKEN_COMMENT2  : '{'  ( . )* '}'  ;


Все это добро разрабатывается, как модуль к NetBeans. Вот вырезка кода лексера

Код


import org.antlr.runtime.*;
import org.netbeans.spi.lexer.Lexer;
import org.netbeans.spi.lexer.LexerRestartInfo;

public class MyLexer  implements Lexer<MyTokenId> {
    private LexerRestartInfo<MyTokenId> info;

    private MyScriptLexer lexer;

    public MyLexer(LexerRestartInfo<MyTokenId> info) {
        this.info = info;
        AntlrCharStream charStream = new AntlrCharStream(info.input(), "My Script Editor");
        lexer = new MyScriptLexer(charStream);
    }

    public org.netbeans.api.lexer.Token<MyTokenId> nextToken() {
        Token token = lexer.nextToken();
        if (token.getType() != MyScriptLexer.EOF) {
            MyTokenId tokenId = MyLanguageHierarchy.getToken(token.getType());
            return info.tokenFactory().createToken(tokenId);
        }
        return null;
    }
...


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

Цитата

SEVERE [global]
java.lang.IllegalStateException: Lexer com.lexer.MyLexer@c91010
  returned null token but lexerInput.readLength()=91
  lexer-state: null
  tokenStartOffset=14, readOffset=105, lookaheadOffset=106
  Chars: "(*)\nprocedure simple(temp1:integer;temp2,temp3:string);\nbegin\n    //do somthing\nend;\n\nEnd.\n" - these characters need to be tokenized.
Fix the lexer to not return null token in this state.


При попытке ввести сочетание "(*" вот в этом коде
Код

(*
procedure simple(temp1:integer;temp2,temp3:string);
begin
    //do somthing
end;

End.


Если же предварительно где-то ввести символы закрывающие многострочный комментарий, то ошибки не возникает

Ну а вопрос в том, можно ли как-то изменить определение многострочного комментария в граммере ANTLR чтобы не писать код обработки в классе лексера.

Пересмотрел много буржуйных ресурсов, однако так и не удалось найти конкретного решения этой проблемы.
Надеюсь, хотя и не сильно, что кто-то сталкивался с подобной ошибкой при разработкой синтаксических анализаторов используя ANTLR =)

PM MAIL   Вверх
dobrolub
Дата 14.12.2010, 23:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 385
Регистрация: 18.12.2009
Где: Vancouver, Canada

Репутация: 11
Всего: 16



глянь на определение для COMMENT_1/2 в pascal.g : http://www.antlr.org/grammar/1279217060704/pascal3.zip

Код

COMMENT_1
        : '(*'
           (
          // ( options { generateAmbigWarnings=false; }                                                        
           :    {input.LA(2) != ')' }? '*'
           |    '\r' '\n'   //  {newline();}                                                                   
           |    '\r'        //  {newline();}                                                                   
           |    '\n'        //  {newline();}                                                                   
           |   ~('*' | '\n' | '\r')
           )*
          '*)'
        {$channel=HIDDEN;}
    ;

COMMENT_2
        :  '{'
           (
           // ( options {generateAmbigWarnings=false;}                                                         
            :   '\r' '\n'      // {newline();}                                                                 
            |   '\r'            //{newline();}                                                                 
            |   '\n'            //{newline();}                                                                 
            |   ~('}' | '\n' | '\r')
            )*
           '}'
        {$channel=HIDDEN;}
    ;



Это сообщение отредактировал(а) dobrolub - 14.12.2010, 23:19
PM   Вверх
PenDaLegi
Дата 14.12.2010, 23:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 14.12.2010
Где: Москва

Репутация: нет
Всего: нет



Это уже пробовал =( Кроме того нынешняя мода ANTLR говорит что такие описания комментариев уже устарели вот тут

В выше приведенном мною примере убраны дополнительные опции. Но я пробовал всячески, пока для всех вариантов исход один и тот же - падает исключение.

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

Код

    public org.netbeans.api.lexer.Token<MyTokenId> nextToken() {
        Token token = lexer.nextToken();
        if (token.getType() != MyScriptLexer.EOF) {
            MyTokenId tokenId = MyLanguageHierarchy.getToken(token.getType());
            return info.tokenFactory().createToken(tokenId);
        }
        LexerInput input = info.input();
        StringBuffer sb = new StringBuffer(lexer.getText());
        int indexOfOpen = sb.toString().split("\\{").length - 1;
        int indexOfClos = sb.toString().split("}").length - 1;
        if (indexOfOpen > indexOfClos) {
             return info.tokenFactory().createToken(MyTokenId.TOKEN_COMMENT2);
        }
        indexOfOpen = sb.toString().split("\\(*").length - 1;
        indexOfClos = sb.toString().split("\\*"+"\\)").length - 1;
        if (indexOfOpen > indexOfClos) {
            return info.tokenFactory().createToken(MyTokenId.TOKEN_COMMENT1);
        }
        return null;
    }




PS. Собственно вот тут есть туториал как добавить поддержку нового языка. Изначально код брал там.

Это сообщение отредактировал(а) PenDaLegi - 15.12.2010, 00:06
PM MAIL   Вверх
ivg
Дата 15.12.2010, 07:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 33
Всего: 81



Код

TOKEN_COMMENT1  : '(*' (options {greedy=false;} : . )* '*)';
?
PM MAIL   Вверх
aleksandy
Дата 15.12.2010, 08:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 260
Регистрация: 17.12.2006

Репутация: 4
Всего: 5



Не знаю поможет или нет, но такой регэксп не учитывает много нюансов. 
Код

"\\(\\*.*\\*\\)"

Вот так можно найти pascal-style комментарии.
Код

    // Самая сложная часть всего регэкспа - это регэксп для многострочного комментария.
    // Разберемся, что означает это монструозное выражение
    // 1 \\(\\* - начало комментария
    // 2 [^*]*\\*+ - текст комментария до одного или нескольких символов "*"
    // 3 (?:[^/*][^*]*\\*+)* - группа, повторяющаяся 0 или более число раз:
    //  3.1 [^\\)*] - символ отличный от закрывающей скобки и не являющийся "*"
    //  3.2 то же, что и (2)
    // 4 \\) - конец комментария
    private final static String COMMENTS_FIND_REGEXP = "(" + // начало группы
                                                       "'[^']*?'" + // предопределенная строка
                                                       ")" + // конец группы
                                                       "|" + // или
                                                       "\\(\\*[^*]*\\*+(?:[^\\(*][^*]*\\*+)*\\)"; 


Монстра взял из книжки Дж.Фридла "Регулярные выражения"

Это сообщение отредактировал(а) aleksandy - 15.12.2010, 08:46
PM   Вверх
PenDaLegi
Дата 15.12.2010, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 14.12.2010
Где: Москва

Репутация: нет
Всего: нет



Цитата(aleksandy @ 15.12.2010,  08:45)
Не знаю поможет или нет, но такой регэксп не учитывает много нюансов. 
Код

"\\(\\*.*\\*\\)"

Вот так можно найти pascal-style комментарии.
Код

    // Самая сложная часть всего регэкспа - это регэксп для многострочного комментария.
    // Разберемся, что означает это монструозное выражение
    // 1 \\(\\* - начало комментария
    // 2 [^*]*\\*+ - текст комментария до одного или нескольких символов "*"
    // 3 (?:[^/*][^*]*\\*+)* - группа, повторяющаяся 0 или более число раз:
    //  3.1 [^\\)*] - символ отличный от закрывающей скобки и не являющийся "*"
    //  3.2 то же, что и (2)
    // 4 \\) - конец комментария
    private final static String COMMENTS_FIND_REGEXP = "(" + // начало группы
                                                       "'[^']*?'" + // предопределенная строка
                                                       ")" + // конец группы
                                                       "|" + // или
                                                       "\\(\\*[^*]*\\*+(?:[^\\(*][^*]*\\*+)*\\)"; 


Монстра взял из книжки Дж.Фридла "Регулярные выражения"

aleksandy: спасибо, очень даже пригодится

Добавлено через 4 минуты и 3 секунды
Цитата(ivg @ 15.12.2010,  07:10)
Код

TOKEN_COMMENT1  : '(*' (options {greedy=false;} : . )* '*)';
?

Да, определение данного токена не фиксирует конца кооментария. Лексер ищет символы конца комментария "*)" натыкается на EOF и вместо токена комментария регистрируется токен конца файла.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1303 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.