Для сравнения выбранных генераторов рассматривалась следующая неоднозначная грамматика:
S -> SSS | SS | a # задается регулярным выражением 'a+'
При подобном описании во время парсинга слов возникает большое количество неоднозначностей, интересно проанализировать, как каждый из парсеров справляется с задачей разбора поступивших на вход данных.
P.S. Та же грамматика может быть описана так:
S -> aS | a
В случае выбора второго способа описания грамматики неоднозначностей не возникает и выражения разбираются за линейное время O(n)
.
Подробные исследования работы каждого генератора можно найти в соответствующих папках проекта.
Для реализации генераторов использовались языки программирования Python3
и Java
(визуализация деревьев в ANTLR)
Изучив выбранные и описанные выше генераторы парсеров, сопоставили их производительность, время работы на одной и той же грамматике, возможности построения деревьев разбора и умение разрешать неоднозначности.
Результаты сравнения времен работы генераторов на неоднозначной грамматике S -> SSS | SS | a
приведены в таблице:
Размер входных данных | ANTLR4 | Lark | Parglare | Yacc |
---|---|---|---|---|
1 | 0.003 | 0.0001 | 0.00035 | 0.00008 |
10 | 0.263 | 0.0077 | 0.014 | 0.00014 |
20 | 33.994 | 0.0418 | 0.264 | 0.00025 |
30 | TL | 0.1155 | 1.911 | 0.00034 |
40 | TL | 0.2598 | 9.906 | 0.00038 |
50 | TL | 0.4973 | 18.399 | 0.00047 |
60 | TL | 0.8868 | 60.883 | 0.00056 |
70 | TL | 1.3198 | 162.57 | 0.00065 |
80 | TL | 2.0565 | 182.499 | 0.00074 |
90 | TL | 2.8626 | 272.041 | 0.00139 |
100 | TL | 4.1458 | 563.266 | 0.00178 |
Не все результаты сравнения можно считать корректными, поскольку одна часть генераторов в обязательном порядке строит дерево/лес разбора при парсинге, а другая -- либо вовсе не имеет возможности воспроизводить графическое представление, либо делает это в опциональном режиме.
Сравнение умения генераторов стоить деревья разбора приведено в таблице ниже:
Генератор | Графическое построение деревьев |
---|---|
ANTLR4 | Дерево, только при сборке под Java |
Lark | Дерево |
Parglare | Дерево (LR) + Лес (GLR) |
Yacc | Нет |
При выборе генератора парсеров пользователю стоит ориентироваться на ситуацию и свои цели.
Как видно из анализа двух рассмотренных выше таблиц, генератор Yacc
не строит деревья разбора, соответственно, это отражается на времени работы программы -- Yacc
отрабатывает быстрее других генераторов. ANTLR4
на строке длиной больше 20-ти символов уже работает слишком долго, однако строит подробные деревья разбора; Parglare
ведет себя похожим образом, но умеет не слишком долго обрабатывать строки длиной уже до 90 символов. Если хочется и относительно небольшое время работы, и наглядное представление парсинга -- наверное, предпочтение следует отдать генератору Lark
.
Также интересно было сопоставить генераторы по принципу "умеет/ не умеет бороться с неоднозначностями, и если да -- то как хорошо". Результаты исследования получились следующими:
Генератор | Умение разрешать неоднозначности |
---|---|
ANTLR4 | Неясно. Четко фиксированных данных и правил нет. |
Lark | Зависит от выбора парсера. Larl (1) не умеет; Earley хорошо и быстро разбирает неоднозначности; CYK тоже справляется, но медленнее. |
Parglare | Строит все возможные варианты разбора строки. |
Yacc | Отлично справляется с неоднозначностями. Правила выбора ветки разбора зафиксированы на уровне языка. |
В частности, сравнительно небольшое время разбора неоднозначной грамматики Lark
на Earley и CYK и Yacc
показывали за счет четко зафиксированных на уровне языка правил, в какую ветку спускаться и какой случай как интерпретировать.