Оптимизирующие парсер-комбинаторы

May 21, 2010 09:00

Оптимизирующие парсер-комбинаторы
Дмитрий Попов

Аннотация

Статья рассказывает о технике парсер-комбинаторов для построения ( Read more... )

#5

Leave a comment

Comments 31

gds May 21 2010, 09:41:10 UTC
let p_float = [...]
Что интересно, этот парсер работает почти вдвое быстрее, чем стандартная окамловская функция float_of_string.

Интересно, почему так получилось?

Reply

alexott May 21 2010, 12:10:45 UTC
в С++ тоже самое - если пользоваться парсером на базе 2-го спирита, то оно быстрее чем atoi

Reply

ext_4199 May 21 2010, 12:49:17 UTC
А все-таки, почему?

Reply

mr_aleph May 21 2010, 12:59:00 UTC
у меня есть ощущение, что стандартные способы разбора типа float_of_string поддерживают более сложные форматы чисел, каким-нибудь более точным способом обрабатывают случаи чисел не представимых в float, а так же учитывают локаль.

Reply


mr_aleph May 21 2010, 13:25:06 UTC
у меня кстати четкое ощущение, что в lua много времени тратится на выделение конкретных подстрочек и вызов функции обработки. какая-то не дешевая операция (видимо сборщик мусора подкачал).

Reply

zoonior May 21 2010, 16:31:50 UTC
На обработку уходит ~20%, и это, скорее всего, да - выделение памяти под строки с флоатами. Я когда писал, знал (во основном со слов Иерусалимского), что LPEG по скорости как YACC/LEX, но такой прыти не ожидал :)

Касательно дальнейших оптимизаций:
1) получилось и так достаточно быстро (быстрее Spirit и Ocamlyacc)
2) специализированные XML парсеры легко дают больше 100 мег/сек - тут мы все равно проиграем :)

Reply

mr_aleph May 21 2010, 17:34:12 UTC
я когда каптчи убрал вообще --- у меня приблизительно в три раза разогналось =)

Reply

zoonior May 22 2010, 05:25:28 UTC
Хм, действительно. Причем, если каптчи заменить на
-> identity_function
скорость все равно сильно проседает (т.е. вроде-бы память непричем). Надо будет на досуге заглянуть в кишки :)

Reply


anonymous May 21 2010, 14:38:46 UTC
В конце раздела 5.3: не совсем понятно про отлов зацикливания при форсировании ленивого значения. Если это действительно просто значение, то OCaml кидает Undefined:

# let rec foo = lazy (Lazy.force foo);;
val foo : 'a Lazy.t =
# Lazy.force foo;;
Exception: CamlinternalLazy.Undefined.

Но в статье форсируются вызовы функций, а это всё равно приводит к зацикливанию:

# let rec bar x = lazy (Lazy.force (bar x));;
val bar : 'a -> 'b Lazy.t =
# Lazy.force (bar 1);;
Stack overflow during evaluation (looping recursion?).

Reply

thedeemon May 22 2010, 03:51:54 UTC
Вот упрощенный вариант той ситуации:

let p_lazy = function [] -> 0 | h::t -> Lazy.force h
let p_real lst = (*42*) p_lazy lst
let rec v = lazy(p_real lst) and lst = v::[];;
print_int (p_lazy lst);;

Если p_real возвращает 42, все работает. Если вызывает p_lazy - бросается Lazy.Undefined.

Типы:
val p_lazy : int Lazy.t list -> int
val p_real : int Lazy.t list -> int
val v : int Lazy.t
val lst : int Lazy.t list

Reply


helvegr May 21 2010, 21:21:18 UTC
Версию на attoparsec можно ускорить примерно на треть, если поменять везде, где можно many/many1 на takeWhile/takeWhile1/skipWhile. Хотя всё равно звёзд с неба не будет хватать.

Reply


dmzlj May 23 2010, 11:35:06 UTC
так парсеры (которые с оптимизацией fsm) в итоге могут рекурсивные структуры разбирать или нет? Вроде получается, что нет, но может я чего-то не заметил?

Reply

permea_kra May 24 2010, 04:59:26 UTC
Конечные автоматы рекурсивные структуры не разбирают в принципе, хоть как они сделаны - в виде комбинаторов, генераторов, регэкспов. Есть специальный формализм автоматов с магазинной памятью, вот они могут разобрать и рекурсивные структуры, но широкого распространения не получили.

Reply

thedeemon May 24 2010, 07:19:11 UTC
В статье автоматы со стеком и возможностью делать что угодно на любом шаге, их возможности пошире.

Reply

permea_kra May 25 2010, 06:39:00 UTC
Это надо почитать.

Reply


Leave a comment

Up