ANTLR — это генератор парсеров, который позволяет создавать парсер по описанию грамматики на одном из основных языков программирования. Он сам написан на java и прекрасно работает с Java.


Пошаговое руководство:


1) Поставить Oracle Java JDK и Intellij Idea, (можно пропустить этот шаг, если они уже поставлены), и запустить Intellij Idea


2) File-Setting-Plugins




Bвести в поле поиска ANTLR и поставить плагин ANTLR v4 grammar plugin. Возможно, понадобится дополнительный поиск по всем репозиториям.




3) Для Maven проекта добавить в pom.xml или создать новый проект.
в dependencies


 <dependency>
            <groupId>org.antlr</groupId>
            <artifactId>antlr4-runtime</artifactId>
            <version>4.7</version>
 </dependency> 

и в plugins


 <plugin>
   <groupId>org.antlr</groupId>
               <artifactId>antlr4-maven-plugin</artifactId>
               <version>4.7</version>
               <executions>
                   <execution>
                       <goals>
                           <goal>antlr4</goal>
                       </goals>
                   </execution>
               </executions>
           </plugin>

Подробности https://github.com/antlr/antlr4/blob/master/doc/java-target.md


4) Далее создам и добавляем вручную файл грамматики с расширением .g4. Имя файла должно совпадать с словом после grammar в первой строчке. Составляется она примерно так: берем то, что нужно парсить, и разбиваем на отдельные токены. Для токенов описываем лексемы, например все английские буквы [a-zA-Z];, все числа [0-9] и т.п.. Для примера взято содержимое примера с официального сайта для файла Hello.g4


// Define a grammar called Hello
grammar Hello;
r  : 'hello' ID ;         // match keyword hello followed by an identifier
ID : [a-z]+ ;             // match lower-case identifiers
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines

5) Далее правой кнопкой мыши кликнуть по второй строчке файла, которая начинается с r и выбрать пункт меню Test Rule r




Внизу откроются окна проверки грамматики. В данном случае, плагин показывает ошибку, скорее всего связанную с тем, что это тестовый пример, однако парсер генерируется. Про это можно почитать здесь https://github.com/antlr/antlr4/issues/118, и пока ее проигнорируем. Но в реальных проектах, надо бы внимательнее обращать внимание на эти ошибки.




6) Кликаем по файлу грамматики правой кнопкой мыши, выбираем пункт меню Configute ANTLR Recoqnizer и генерируем парсер




После этого появится в правом нижнем углу сообщение об успехе


7) Далее снова кликаем по файлу правой кнопкой мыши и выбираем пункт меню Configute ANTLR,




и выходит окно для конфигурирования генерации файлов




В этом окне вводим данные о папке назначения и языке программирования, в нашем случае Java, нужны ли visitor или listener, а также другую требуемую информацию, и нажимаем кнопку ОК




И ANTLR после этого генерирует файлы для распознавания. Тем не менее, хотя выходной каталог указан, часто создается новая папка gen в корне проекта, причем java не распознает эти файлы.




Для того, чтобы java увидела эти файлы, папку нужно либо пометить правой кнопкой мыши «Mark Directory As» на «Generated Sources Root» на папку gen.





И должно получится так:





8) ANTLR сгенерировал такие классы:


Класс HelloParser.java — это описание класса парсера, то есть синтаксического анализатора, отвечающего грамматике Hello:


 public class HelloParser extends Parser { ... }

Класс HelloLexer.java — это описание класса лексера, или лексического анализатора, отвечающего грамматике HelloInit:


 public class HelloLexer extends Lexer { ... }

Hello.tokens, HelloLexer.tokens — это вспомогательные классы, которые содержат информацию о токенах HelloListener.java, HelloBaseListener.java, HelloBaseVisitor, HelloVisitor — это классы, содержащие описания методов, которые позволяют выполнять определенный действия при обходе синтаксического дерева


9) После этого добавим класс HelloWalker (хотя это класс не обязателен, этот код можно изменить и добавить в Main для вывода информации)


  public class HelloWalker extends HelloBaseListener {
    public void enterR(HelloParser.RContext ctx ) {
        System.out.println( "Entering R : " + ctx.ID().getText() );
    }

    public void exitR(HelloParser.RContext ctx ) {
        System.out.println( "Exiting R" );
    }
}

10) И, наконец, класс Main — точка входа в программу


  public class Main {
    public static void main( String[] args) throws Exception
    {
       HelloLexer lexer = new HelloLexer(CharStreams.fromString("hello world"));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        HelloParser parser = new HelloParser(tokens);
        ParseTree tree = parser.r();
        ParseTreeWalker walker = new ParseTreeWalker();
        walker.walk(new HelloWalker(), tree);
    }
}

11) Запускаем метод main, и получаем на выходе в консоли успешно отработанный парсинг


Entering R : world
Exiting R

> Код проекта выложен здесь

Комментарии (8)


  1. grossws
    07.11.2017 20:02

    Если уж используете antlr4-maven-plugin и, собственно, maven, то лучше уж использовать принятые соглашения: *.g4 располагать в src/main/antlr4/, сгенерированные файлы будут лежать в target/generated-sources/antlr4/, которую IDEA автоматически пометит как generated sources root.


    Также, ANTLRInputStream deprecated, так что лучше использовать CharStreams.from* (CharStreams.fromString в данном случае).


    1. savimar Автор
      07.11.2017 21:53

      В target/generated-sources/antlr4/ Idea не помечает generated sources root, ни автоматически,
      ни вручную, вообще их не видит, (да и не должна видеть эти файлы), так что вернула в gen, остальное исправлено


      1. grossws
        08.11.2017 13:22

        В target/generated-sources/antlr4/ Idea не помечает generated sources root, ни автоматически, ни вручную, вообще их не видит, (да и не должна видеть эти файлы)

        У меня 2017.2.5 помечает автоматически. Вы уверены, что у вас maven-проект, а не что-нибудь другое, куда pom.xml добавился позже? Если не удаётся пометить вручную — идите в youtrack.jetbrains.com, УМВР.


        С чего вы взяли, что IDEA не должна их видеть я не понял. У меня аналогично видятся файлы в target/generated-sources/annotations, сгенерированные org.immutables:value.


    1. KvanTTT
      08.11.2017 00:40

      Также, ANTLRInputStream deprecated

      Устарел, но при этом не понятно как, например, на новом API просто заюзать регистронезависимый поток? А он много где используется: диалекты SQL, PHP. Автор ANTLR консервативен и без особо охоты мержит риквесты с фичами, однако из-за нововведений с юникодом приходится использовать такие вот deprecated классы.


      1. grossws
        08.11.2017 13:39

        А где в antlr4 ANTLRInputStream даёт поддержку case insensitive? Мне пока не приходилось развлекаться с регистронезависимыми языками. Нельзя ли её сделать на уровне создания TokenStream?


        1. KvanTTT
          08.11.2017 13:52

          А где в antlr4 ANTLRInputStream даёт поддержку case insensitive? Мне пока не приходилось развлекаться с регистронезависимыми языками.

          Пока что поддерживается в плагине antlr4test-maven-plugin и используется для грамматик в оффициальном репозитории.


          Но, возможно, скоро он будет доступен и из коробки: https://github.com/antlr/antlr4/pull/2046


          Нельзя ли её сделать на уровне создания TokenStream?

          У меня пока что особо не получалось, вот даже вопрос на stackoverflow создавал.


          1. grossws
            08.11.2017 16:06

            Понятно. Мне пока не актуально, но спасибо за развёрнутый ответ.


  1. Hixon10
    07.11.2017 21:42

    Отличное введение в тему — tomassetti.me/antlr-mega-tutorial

    Готовые грамматики для много чего — github.com/antlr/grammars-v4