2007-05-07

Parser Combinators

It's not too bad, code comes out rather beautiful, short and clear. True, for that purpose I had to quickly look into haskell syntax.

I've written a piece of tasks from the first chapter of SICP in haskell as the warm-up, read the sixth chapter of the first book of _darkus_

And by motifs I've gotten the following parser of pl/sql packages specifications:

terminal = (spaces . utoken)
where utoken t s | lower t == lower (take n s) = [(lower (drop n s),t)]
| otherwise = []
where n = length t
lower = map toLower

-- Разрешенные идентификаторы
ident = spaces ((satisfy isAlpha) <:*> zeroOrMore leastChars) <@ (map toLower)
where leastChars = choise [satisfy isAlpha,
satisfy isDigit,
symbol '.',
symbol '_']

comment = single_line_comment <|> multi_line_comment
where single_line_comment = pack (token "--")
(zeroOrMore (satisfy (\_->True)))
(zeroOrMore (symbol '\n'))
multi_line_comment = reverse . p
where p = pack (token "/*") (zeroOrMore (satisfy (\_->True))) (token "*/")

-- Базовые типы
pls_type = choise [terminal "integer",
terminal "varchar2",
terminal "number",
terminal "date",
field_type]
where field_type = ident <* spaces(symbol '%') <*> terminal "type"

-- Разделители
sep_semicolon = spaces (symbol ';')
sep_comma = spaces (symbol ',')

-- Общие части выражений
def_var = ident <*> ((param_type) <|> succeed "in") <*> spaces (pls_type)
where param_type = choise [terminal "in",
terminal "out",
(terminal "in" <*> terminal "out") <@ (\_ -> "in out")]

def_params = spaces ((parens var_list) <|> succeed [])
where var_list = (listOf def_var sep_comma) <|> succeed []

def_fun = ident <*> def_params

-- Спецификации
spec_procedure = terminal "procedure" *> def_fun <*> (succeed "None") <* sep_semicolon
spec_function = terminal "function" *> def_fun <*> terminal "return"
*> ident <* sep_semicolon
spec_declaration = spec_procedure <|> spec_function

spec_create_package = cr_or_repl <*> (terminal "package") *> ident <*> terminal "as"
*> zeroOrMore spec_declaration
<* terminal "end" <* sep_semicolon <* terminal "/"
where cr_or_repl = terminal "create" <:*> option (terminal "or" *> terminal"replace")


Evidently, parser in python intends to the same approach.
Now I have to look into the system of haskell types and classes to have a possibility of digestible using the parser results.

No comments:

Post a Comment