Использование и архитектураParsec

Содержание

Слайд 2

Синтаксический анализ

Задачи:
Проверка правильности исходных данных - соответствие текста грамматике
Содержательная обработка исходных данных

Синтаксический анализ Задачи: Проверка правильности исходных данных - соответствие текста грамматике Содержательная обработка исходных данных

Слайд 3

Подходы

Полностью ручная реализация
Генераторы парсеров (YACC, Happy)
Комбинаторные библиотеки
“List of successes”
Монадические
Parsec

Подходы Полностью ручная реализация Генераторы парсеров (YACC, Happy) Комбинаторные библиотеки “List of successes” Монадические Parsec

Слайд 4

Монадические парсеры

type Parser a
return :: a -> Parser a
(>>=) :: Parser a

Монадические парсеры type Parser a return :: a -> Parser a (>>=)
-> (a -> Parser b) -> Parser b
satisfy :: (Char -> Bool) -> Parser Char
(<|>) :: Parser a -> Parser a -> Parser a

Слайд 5

Parsec

import Text.ParserCombinators.Parsec
simple :: Parser Char
simple = letter
> parseTest simple “a”
‘a’
Примитивные парсеры: letter,

Parsec import Text.ParserCombinators.Parsec simple :: Parser Char simple = letter > parseTest
char, string, …

Слайд 6

Последовательность парсеров

bracketedLetter :: Parser Char
bracketedLetter = do { char ‘(‘
; c

Последовательность парсеров bracketedLetter :: Parser Char bracketedLetter = do { char ‘(‘
<- letter
; char ‘)’
; return c
}

Слайд 7

Последовательность парсеров

> parseTest bracketedLetter “(a)”
‘a’
> parseTest bracketedLetter “(ab)”
parse error at (line 1,

Последовательность парсеров > parseTest bracketedLetter “(a)” ‘a’ > parseTest bracketedLetter “(ab)” parse
column 3):
unexpected "b"
expecting ")"

Слайд 8

Альтернативы

parens :: Parser ()
parens = do { char ‘(‘
; parens
;

Альтернативы parens :: Parser () parens = do { char ‘(‘ ;
char ‘)’
; parens
}
<|> return ()

Слайд 9

Предпросмотр

test1 = string “OCaml” <|> string “Haskell”
test2 = string “(lisp)” <|> string

Предпросмотр test1 = string “OCaml” string “Haskell” test2 = string “(lisp)” string
“(scheme)”
> parseTest test1 “Haskell”
“Haskell”
> parseTest test2 “(lisp)”
“(lisp)”

Слайд 10

Предпросмотр

test1 = string “OCaml” <|> string “Haskell”
test2 = string “(lisp)” <|> string

Предпросмотр test1 = string “OCaml” string “Haskell” test2 = string “(lisp)” string
“(scheme)”
> parseTest test2 “(scheme)”
parse error at (line 1, column 1):
unexpected "s"
expecting "(lisp)"

Слайд 11

Предпросмотр

Причина: Parsec строит LL(1)-парсер
Ограничение: решение принимается на основании анализа только первого символа

Предпросмотр Причина: Parsec строит LL(1)-парсер Ограничение: решение принимается на основании анализа только
строки
Осознанный выбор: эффективность
Есть возможность преодолеть ограничения LL(1)

Слайд 12

Предпросмотр

Вариант 1:
test2 = do { char ‘(‘
; s <- string “lisp”

Предпросмотр Вариант 1: test2 = do { char ‘(‘ ; s string
<|> string “scheme”
; char ‘)’
; return ( “(“ ++ s ++ “)” )
}

Слайд 13

Предпросмотр

Вариант 2:
test2 = try (string “(lisp)”) <|> string “(scheme)”
Комбинатор try так изменяет

Предпросмотр Вариант 2: test2 = try (string “(lisp)”) string “(scheme)” Комбинатор try
наш парсер, что он в случае неудачи оставляет уже прочитанные символы в потоке

Слайд 14

Архитектурные принципы

Эффективность: отказ от затрат на поддержку неограниченного предпросмотра, LL(1) по умолчанию,

Архитектурные принципы Эффективность: отказ от затрат на поддержку неограниченного предпросмотра, LL(1) по
можно увеличить количество просматриваемых символов, используя try
Информативность сообщений об ошибках

Слайд 15

Ограничение предпросмотра

В конструкции p <|> q парсер q в принципе не вызывается,

Ограничение предпросмотра В конструкции p q парсер q в принципе не вызывается,
если p обработал больше одного символа
Каждый парсер отслеживает, сколько символов он обработал

Слайд 16

Ограничение предпросмотра

Упрощенная реализация:
type Parser a = String -> Consumed a
data Consumed a

Ограничение предпросмотра Упрощенная реализация: type Parser a = String -> Consumed a
= Consumed (Reply a)
| Empty (Reply a)
data Reply a = Ok a String | Error

Слайд 17

Базовые комбинаторы

return x = \input -> Empty (Ok x input)
satisfy :: (Char

Базовые комбинаторы return x = \input -> Empty (Ok x input) satisfy
-> Bool) -> Parser Char
satisfy test = \input -> case (input) of
[] -> Empty Error
(c:cs) | test c -> Consumed (Ok c cs)
| otherwise -> Empty Error

Слайд 18

Базовые комбинаторы

char c = satisfy (==c)
letter = satisfy isAlpha
digit = satisfy isDigit

Базовые комбинаторы char c = satisfy (==c) letter = satisfy isAlpha digit = satisfy isDigit

Слайд 19

Базовые комбинаторы

(>>=) :: Parser a -> (a -> Parser b) -> Parser

Базовые комбинаторы (>>=) :: Parser a -> (a -> Parser b) ->
b
p >>= f = \input -> case (p input) of
Empty reply1
-> case (reply1) of
Ok x rest -> ((f x) rest)
Error -> Empty Error
...

Слайд 20

Базовые комбинаторы

Consumed reply1
-> Consumed
(case (reply1) of
Ok x rest ->

Базовые комбинаторы Consumed reply1 -> Consumed (case (reply1) of Ok x rest
case ((f x) rest) of
Consumed reply2 -> reply2
Empty reply2 -> reply2
error -> error)

Слайд 21

Базовые комбинаторы

(<|>) :: Parser a -> Parser a -> Parser a
p <|>

Базовые комбинаторы ( ) :: Parser a -> Parser a -> Parser
q = \input -> case (p input) of
Empty Error -> (q input)
Empty ok -> case (q input) of
Empty _ -> Empty ok
consumed -> consumed
consumed -> consumed

Слайд 22

try

try :: Parser a -> Parser a
try p = \input -> case

try try :: Parser a -> Parser a try p = \input
(p input) of
Consumed Error -> Empty Error
other -> other

Слайд 23

Обработка ошибок

К типу Parser добавляется состояние:
type Parser a = State -> Consumed

Обработка ошибок К типу Parser добавляется состояние: type Parser a = State
a
data State = State String Pos
К результатам разбора добавляется сообщение об ошибках, причем к удачному разбору – тоже
data Message = Message Pos String [String]
data Reply a = Ok a State Message | Error Message

Слайд 24

Обработка ошибок

Меняется реализация return, satisfy, (<|>) – [Leijen, Meijer, 2001]
В результате получаем

Обработка ошибок Меняется реализация return, satisfy, ( ) – [Leijen, Meijer, 2001]
возможность приписывать парсерам информативные обозначения – комбинатор

Слайд 25

Семантика

nesting :: Parser Int
nesting = do { char ‘(‘
; n <-

Семантика nesting :: Parser Int nesting = do { char ‘(‘ ;
nesting
; char ‘)’
; m <- nesting
; return (max (n + 1) m)
} <|> return 0

Слайд 26

Дополнительные возможности

Лексический анализ:
Лексический анализ объединяется с синтаксическим анализом
Лексический анализ выполняется отдельными специализированными

Дополнительные возможности Лексический анализ: Лексический анализ объединяется с синтаксическим анализом Лексический анализ
парсерами
Реализованными в библиотеке
Разработанными самостоятельно с помощью комбинаторов
Использование отдельного сканера, параметризация по типу потока (не только Char)
Возможность генерации парсера выражений по набору операций с учетом ассоциативности и приоритета