3. Apama EPL Plugin
1. Подсветка синтаксиса
2. Проверка синтаксиса
3. Навигация по ссылкам
– Программные конструкции определенные внутри
одного файла
– Внешние ссылки
Apama Event Processing Language
on Event A
Event A Event B
on Event B
correlator monitors
4.
5. Теория
• Alfred V. Aho, Compilers: Principles,
Techniques & Tools
• Terence Parr, Language Implementation
Patterns
• https://confluence.jetbrains.com/display/IDEA
DEV/Developing+Custom+Language+Plugins+f
or+IntelliJ+IDEA
6. поток символов
Лексический анализатор (Lexer)
Синтаксический анализатор (Parser)
поток лексем
синтаксическое дерево
Остальные фазы компиляции
Процесс компиляции
Таблица символов
7. Лексический анализатор
Пусть исходная программа содержит инструкцию присваивания:
position = initial + rate * 60
Символы в этом присваивании могут быть сгруппированы в следующие лексемы и
отображены в следующие токены, передаваемые синтаксическому анализатору:
1. position (id, 1)
2. = (=, нет значения атрибута) (=)
3. initial -> (id, 2)
4. + (+)
5. rate (id, 3)
6. * (*)
7. 60 (number, 4)
Выходной поток токенов после лексического анализа будет иметь вид:
(id, 1) (=) (id, 2) (+) (id, 3) (*) (id, 4)
1 position …
2 initial …
3 rate …
4 60 …
… … …
8. Синтаксический анализатор
Синтаксический анализатор использует первые компоненты токенов, полученных при
лексическом анализе, для создания древовидного промежуточного представления, которое
описывает грамматическую структуру потока токенов.
поток токенов (id, 1) (=) (id, 2) (+) (id, 3) (*) (id, 4)
синтаксическое дерево (=)
/
(id, 1) (+)
/
(id, 2) (*)
/
(id, 3) (id, 4)
9. Грамматика
Иерархическая структура множества конструкций языка программирования может быть
описана с помощью контекстно свободных грамматик, состоящих из:
1. Терминалы
2. Нетерминалов
3. Продукции
4. Один из нетерминальных символов, указываемый как стартовый или начальный.
boolean_literal ::= true | false
decimal_literal ::= ( '-' | '+' )* ( DECIMAL | ( DIGIT+ DOT? ) )
где
DIGIT = 'regexp:[0-9]+'
10. Грамматика
Грамматика определяется перечислением ее продукций, причем первой
указывается продукция для стартового символа. Грамматика выводит, или порождает,
строки, начиная со стартового символа и неоднократно замещая нетерминалы телами
продукций этих нетерминалов. Строки токенов, порождаемые из стартового символа,
образуют язык, определяемый грамматикой.
Грамматика может быть описана в форме Бэкуса — Наура или представлена графически в
виде railroad diagram.
program ::= package_specification? using_declaration+ ( event_declaration+ | monitor_declaration )
11. Разбор (Parsing)
Синтаксический анализ, или разбор, представляет собой выяснение для полученной
строки терминалов способа ее вывода из стартового символа грамматики. Если строка не
может быть выведена из стартового символа, синтаксический анализатор сообщает об
ошибке в строке.
Задачу синтаксического анализа можно представить как построение дерева разбора.
S ::= xyz | aBC
грамматика: B ::= c | cd строка: acddf
C ::= eg | df
S S S S S
| / | / | / | / |
a B C a B C a B C a B C
| | / | / | |
c c d c d d f
12. Инструменты
1. Jetbrains IDEA Community Edition
• Языково-независимая часть платформы
• Специфическая для конкретного языка
2. git clone git://git.jetbrains.org/idea/community.git idea
3. Плагины:
• Plugin DevKit
Набор инструментов для разработки плагинов под платформу Intellij IDEA
• Grammar-Kit
Плагин для описания грамматик в форме Бэкуса — Наура
• PsiViewer
Intellij IDEA Program Structure Interface
19. Запуск плагина
Jetbrains IDEA logs: https://devnet.jetbrains.com/docs/DOC-181
При запуске Run / Debug Configuration и создании нового файла с зарегистрированным
расширением IDEA автоматически ассоциирует его с разрабатываемым плагином.
20. Реализация лексического анализатора
Лексический анализатор (lexer) – база для всего дальнейшего функционала Custom
Language Plugin.
IDEA вызывает lexer в трех основных контекстах:
1. Подсветка синтаксиса
2. Построение синтаксического дерева файла
3. Построение индекса слов содержащихся в файле
Лексический анализатор для IDEA можно создать:
1. Реализацией интерфейса com.intellij.lexer.Lexer
2. Используя генератор лексических анализаторов JFlex (jflex.de)
JFlex генерирует лексические анализаторы на основе *.flex файлов, которые в свою очередь
могут быть сгенерированы из грамматики при помощи IDEA GrammarKit Plugin.
21. Процесс синтаксического анализа в IDEA
1. Построение абстрактного синтаксического дерева (AST), определяющее структуру
программы
monitor M { monitor_declaration
} |
+-- monitor
|
+-- identifier
|
+-- {
|
+-- }
2. Во второй фазе строится PSI (Program Structure Interface) дерево поверх AST,
добавляя семантику и методы для манипуляции языковыми конструкциями
Синтаксический анализатор для IDEA можно создать:
1. Реализацией интерфейса com.intellij.lang.PsiParser
2. Сгенерировать из грамматики используя IDEA Grammar-Kit Plugin
23. PsiViewer Plugin
Для отладки PSI структур удобно использовать IDEA PsiViewer Plugin. С его помощью можно
смотреть структуру PSI дерева для целевого языка, свойства каждого PSI элемента и
отображение исходного кода на соответствующую структуру PSI элементов.
24. Грамматика EPL
Грамматика EPL описывается в файле epl.bnf. На ее основе средствами IDEA Grammar-Kit
Plugin возможна генерация совместимых с платформой лексических и синтаксических
анализаторов.
BNF файл грамматики состоит из трех разделов:
1. Секции заголовка:
parserClass="com.intellij.epl.parser.EplParser“
psiClassPrefix="Epl"
psiImplClassSuffix="Impl"
psiPackage="com.intellij.epl.psi"
psiImplPackage="com.intellij.epl.psi.impl"
elementTypeHolderClass="com.intellij.epl.psi.EplTypes"
elementTypeClass="com.intellij.epl.psi.EplElementType"
tokenTypeClass="com.intellij.epl.psi.EplTokenType"
psiImplUtilClass="com.intellij.epl.psi.EplPsiImplUtil"
25. Грамматика EPL
2. Секции лексем, которые возможно при необходимости задать регулярными
выражениями для удобства их последующего использования:
tokens=[
ID = 'regexp:[a-zA-Z_$][a-zA-Z0-9_$]*'
DIGIT = 'regexp:[0-9]+'
DECIMAL = 'regexp:[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?'
NON_EMPTY_STRING = 'regexp:"([^"]|.)*"'
EMPTY_STRING = '""'
DOCUMENTATION = 'regexp:/**([^*]|[rn]|(*+([^*/]|[rn])))**+/'
BLOCK_COMMENT = 'regexp:/*([^*]|[rn]|(*+([^*/]|[rn])))**+/'
LINE_COMMENT = 'regexp://.*'
OP_ASSIGNMENT = ":="
OP_PLUS = "+"
OP_MINUS = "-"
OP_AR_MUL = "*"
OP_AR_DIV = "/"
28. Формат flex файлов
Flex файл представляет собой спецификацию, на основе которой будет сгенерирован java
класс лексического анализатора. Основными его разделами являются:
1. Определение пакета лексического анализатора и импортируемых зависимостей
package com.intellij.epl;
import com.intellij.lexer.*;
import com.intellij.psi.tree.IElementType;
import static com.intellij.epl.psi.EplTypes.*;
2. Кода, который следует включить в неизменном виде в создаваемый класс:
%{
public _EplLexer() {
this((java.io.Reader)null);
}
%}
29. Формат flex файлов
3. Модификатора доступа создаваемого класса, его имени и реализуемых интерфейсов
%public
%class _EplLexer
%implements FlexLexer
4. Типа элементов создаваемых лексем:
%type IElementType
5. Последовательности символов описываемых регулярными выражениями:
EOL="r"|"n"|"rn"
LINE_WS=[ tf]
WHITE_SPACE=({LINE_WS}|{EOL})+
ID=[a-zA-Z_$][a-zA-Z0-9_$]*
DIGIT=[0-9]+
DECIMAL=[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?
31. Генерация лексического и
синтаксического анализаторов
1. Генерация лексического анализатора в IDEA происходит в два этапа:
генерация файла *.flex из файла грамматики *.bnf
Grammar-Kit -> Generate JFlex Lexer
генерация лексического анализатора на основе сгенерированного
*.flex файла
Grammar-Kit -> Run JFlex Generator
2. Синтаксический анализатор генерируется из из файла грамматики
*.bnf
Grammar-Kit -> Generate Parser Code
32. Реализация класса подсветки синтаксиса
Подсветка синтаксиса реализуется отображением классов лексем на
соответствующие инстансы com.intellij.openapi.editor.colors.TextAttributesKey
35. Навигация по структуре программы
Ссылка (на переменную, метод и т. д. ) представляет собой указатель на один из узлов
дерева и может находиться либо в текущем, либо во внешнем файле.
36. Навигация по структуре программы
Реализация метода getReference() должна возвращать конкретный узел PSI дерева, который
откроется в текстовом редакторе.
37. Что дальше?
• Find Usages
• Code Completion
• Остальные фичи IDEA для Custom Language
IntelliJ IDEA Custom Languages repo:
https://plugins.jetbrains.com/category/index?pr=idea&category_id=48