Грамматики в Java, Perl 6 и Perl 5

Грамматики представляют собой в общем случае набор "правил", с помощью которых можно определить языковые конструкции, поддерживающие так же произвольную вложенность. Сфера применения грамматик - сложный синтаксический анализ текста или данных [1].

Без грамматик не обойтись, в случаях создания компиляторов языков, интерпретаторов и т.д. В последнее время я плотно использую грамматики в Java, Perl 6 и Perl 5. Вкратце выскажусь о них в каждом из языков.

Грамматики в Java

JavaCC (Java Compiler Compiler), пожалуй, наиболее распространенный генератор парсеров для Java. Включает в себя утилиту JJTree для построения синтаксических деревьев.

Синтаксис определения правила простой: элемент грамматики, список элементов грамматики и альтернативный список. Например, следующим токеном определяются цифры и числа:

TOKEN:
 {
  < NUMBER: (<DIGIT>)+ ( "." (<DIGIT>)+ )? >
  | < DIGIT: ["0"-"9"] >
  }

Примеры грамматик можно найти в репозитории JavaCC грамматик [2].

Грамматики в Perl 6

В Perl 6 грамматики являются частью языка и это одна из самых замечательных фитч языка. Поэтому ничего удивительного нет в том, что синтаксис Perl 6 описан с помощью его же грамматик [3].

Грамматики в Perl 6 фактически представлены в виде классов и могут наследовать другие грамматики. Процесс обработки текста может быть совмещен с построением синтаксического дерева. Для этого парсеру передается параметр action, значением которого является объект обрабатывающий совпадения токенов (в Perl 6 ими являются лексемы token и rule).

Например:

my $res = Plosurin::Grammar.parse($txt, :actions(Plosurin::Actions.new ));

При обработке $txt, в случае совпадения токена, для построения абстрактного синтаксического дерева (AST) будут вызваны методы объекта Plosurin::Actions. Результаты вызовов станут частью результирующего дерева.

Такая интеграция в язык программирования позволяет упростить использование грамматик. Насколько ? Можно к примеру сравнить определение грамматики для обработки JSON для JavaCC [4] и Perl 6 [5] (для наглядности в одном gist [6]).

Грамматики в Perl 5

Для Perl 5 грамматики реализованы в виде библиотеки Regexp-Grammars [7].

Следующий пример из документации, демонстрирует правила для парсинга LaTeX:

use Regexp::Grammars;
    $parser = qr{
        <File>
        <rule: File>       <[Element]>*
        <rule: Element>    <Command> | <Literal>
        <rule: Command>    \\  <Literal>  <Options>?  <Args>?
        <rule: Options>    \[  <[Option]>+ % (,)  \]
        <rule: Args>       \{  <[Element]>*  \}
        <rule: Option>     [^][\$&%#_{}~^\s,]+
        <rule: Literal>    [^][\$&%#_{}~^\s]+
    }xms;

Тем, кто немного знаком с грамматиками Perl 6, приведенный выше пример покажется знакомым.

Внешне и по возможностям Regexp-Grammars очень близка к грамматикам Perl 6: есть наследование, построение синтаксического дерева. А в плане отладки правил функционал даже превосходит Perl 6.

Regexp::Grammars одна из тех библиотек, которые знать очень полезно!

[1]Синтаксический анализ и инструментарий. http://ru.wikipedia.org/wiki/Синтаксический анализ

[2]Репозиторий JavaCC грамматик. http://java.net/projects/javacc/downloads/directory/contrib/grammars

[3]Грамматика Perl 6. https://raw.github.com/perl6/std/master/STD.pm6

[4]Определение грамматики JSON для JavaCC.http://java.net/downloads/javacc/contrib/grammars/JSONParser.jj

[5]Грамматика JSON в Perl 6. https://raw.github.com/moritz/json/master/lib/JSON/Tiny/Grammar.p

[6]Грамматики обработки JSON для JavaCC и Perl 6. https://gist.github.com/1363580

[7]Библиотека грамматического анализа для Perl 5 Regexp-Grammars. http://search.cpan.org/dist/Regexp-Grammars/