Дело в том, что на самом деле эта библиотека комбинатора синтаксического анализатора Packrat не является полной реализацией алгоритма Пакрата, а скорее похожа на набор определений, которые можно повторно использовать между различными синтаксическими анализаторами пакета.
Реальная хитростьПакетный алгоритм (а именно запоминание результатов разбора) происходит в другом месте.Посмотрите на следующий код (взятый из тезиса Форда):
data Derivs = Derivs {
dvAdditive :: Result Int,
dvMultitive :: Result Int,
dvPrimary :: Result Int,
dvDecimal :: Result Int,
dvChar :: Result Char}
pExpression :: Derivs -> Result ArithDerivs Int
Parser pExpression = (do char ’(’
l <- Parser dvExpression
char ’+’
r <- Parser dvExpression
char ’)’
return (l + r))
</> (do Parser dvDecimal)
Здесь важно отметить, что рекурсивный вызов синтаксического анализатора выражений сам по себе прерывается (в некотором роде открытой рекурсии)просто проецируя соответствующий компонент структуры Derivs.
Этот рекурсивный узел затем связывается в «функции рекурсивного связывания» (снова взятой из тезиса Форда):
parse :: String -> Derivs
parse s = d where
d = Derivs add mult prim dec chr
add = pAdditive d
mult = pMultitive d
prim = pPrimary d
dec = pDecimal d
chr = case s of
(c:s’) -> Parsed c (parse s’)
[] -> NoParse
Эти фрагментыдействительно, где трюк с пакратом происходит.Важно понимать, что этот прием не может быть реализован стандартным способом в традиционной библиотеке комбинатора синтаксического анализатора (по крайней мере, на чистом языке программирования, таком как Haskell), потому что он должен знать рекурсивную структуру грамматики.Существуют экспериментальные подходы к библиотекам комбинаторов синтаксического анализатора, которые используют конкретное представление рекурсивной структуры грамматики, и там можно обеспечить стандартную реализацию Packrat.Например, моя собственная библиотека грамматических комбинаторов (не поддерживается atm, извините) предлагает реализацию Packrat .