Функциональные парсеры: различия между версиями
Содержимое удалено Содержимое добавлено
→Тип <tt>Parser</tt>: Идентификаторы заключены в <tt> |
|||
Строка 23:
== Тип <tt>Parser</tt> ==
Задачей синтаксического анализа является построение дерева, описывающего структуру заданной строки. В функциональном языке мы можем определить тип данных <tt>Tree</tt> (дерево). Парсер может быть реализован посредством функции следующего типа:
type Parser
Для разбора подструктур парсер может вызвать другие парсеры или рекурсивно самого себя. Этим вызовам необходимо обмениваться не только своими результатами, но и информацией о том, какая часть входной строки осталась необработанной. Поскольку это не может быть сделано при помощи глобальной переменной, необработанная часть входной строки должна быть частью результата работы анализатора. Два результата могут быть сгруппированы в кортеж. Более удачным определением для типа <tt>Parser</tt> является следующее:
type Parser
Тип <tt>String</tt> определён в
type Parser a
Например, анализатор, возвращающий структуру типа <tt>Oak</tt> теперь имеет тип <tt>Parser Oak</tt>. Для деревьев разбора, представляющих структуру <tt>Expression</tt> (выражение) мы можем определить тип <tt>Expr</tt>, делая возможным разработку анализатора, возвращающего выражение: <tt>Parser Expr</tt>. Другим примером анализатора является функция, распознающая строку цифр и возвращающая число, представленное этой строкой, в качестве «дерева разбора». В этом случае данная функция имеет тип <tt>Parser Int</tt>.
До сих пор мы предполагали, что каждая строка может быть разобрана ровно одним способом. В общем случае это предположение не обязательно верно: одна строка может быть разобрана различными способами или может не существовать ни одного способа разбора строки. В качестве ещё одного усовершенствования определения типа мы допустим, что вместо одного дерева разбора (и связанной с ним необработанной частью строки) парсер возвращает список деревьев. Каждый элемент результата является списком, состоящим из дерева и части строки, оставшейся необработанной после разбора. Следовательно, более подходящим является следующее определение типа <tt>Parser</tt>:
type Parser a
Если существует единственный разбор, то результатом работы функции-анализатора будет список, состоящий из одного элемента. Если разбор провести невозможно, то результатом будет пустой список. В случае неоднозначной грамматики элементами результирующего списка будут альтернативные варианты разбора.
Этот метод называется «список благоприятных исходов», его описал Вадлер (Wadler)
Парсеры имеющий тип, описываемый нами до сих пор, работают со строками, которые являются списками символов. Однако, это не мешает допустить разбор строк, состоящих из элементов, отличных от символов. Можно предположить ситуацию, когда препроцессор подготавливает список лексем, который затем разбирается. Чтобы учесть этот случай, в качестве последнего усовершенствования типа парсера, мы снова абстрагируемся от типа — от типа элементов входной строки. Обозначив его <tt>а</tt>, а тип результата <tt>b</tt>, можно определить тип парсера следующим образом:
type Parser a b
или так, если вы предпочитаете кратким идентификаторам более выразительные:
type Parser symbol result
Мы будем использовать это определение типа в оставшейся части данной статьи.
|