Arc Forumnew | comments | leaders | submitlogin
Parser combinator library for trees
7 points by raymyers 5893 days ago | 1 comment
I am working on a library for parsing and transforming trees. See "lib/treeparse.arc" and "lib/treeparse-examples.arc" in Anarki. It is based on work such as Parsec[1] and sjs's parsecomb[2]. The main difference is that this will operate on lists and trees rather than strings.

    [1] http://legacy.cs.uu.nl/daan/parsec.html
    [2] http://arclanguage.org/item?id=1430
There are three basic ways parsers can be constructed (other than by creating new primitives.)

    * A parser for some atom is the literal itself -- i.e. (parse 'a input) will succeed on input '(a).
    * A parser for sublists is a list of parsers -- this gives us the ability to parse arbitrary trees.
    * More complex parsers can be formed by combining parsers -- using combinators.
Parser combinators are operators for constructing more elaborate parsers from simpler ones. Some of the more common ones are alt, many, seq, and maybe.

Consider a simple parser which says "I expect to see zero or more a's, followed by either b or c, followed optionally by d". Here's how we could use combinators to construct it.

    ;;; S ::= [a*] {b | c} [d]
    (= S (seq (many 'a) (alt 'b 'c) (maybe 'd)))
S is now a parser for the grammar given above. Here are some of the inputs that S would accept.

    '(b)
    '(c)
    '(c d)
    '(b d)
    '(a b d)
    '(a a a b d)
Now we can do something a little more interesting. Tree parsing is especially useful for defining Lisp macros, because macros are essentially transformations on trees. To manipulate subtrees, we can use the filt combinator to attach a filter function to a parser. Here is a cond macro to convert conventional Lisp cond to Arc's if and do.

    (= forms (filt [list:cons 'do _] (many anything)))
    (= clause (filt car (list (seq anything forms))))
    (= S (filt [cons 'if _] (many clause)))
    (mac cond clauses (parse-all S clauses))


3 points by raymyers 5892 days ago | link

To show more of what is possible, "lib/treeparse-examples.arc" shows how to define the 20-line hcase2 macro, a pattern matching case statement that extends defpat with guard clauses and some infix sugar.

    (def union (< xs ys)
      "Merge two sorted lists, discarding duplicates."
      (hcase2 `(,xs ,ys)
        xs () = xs
        () ys = ys
        (x . xt) (y . yt)
        || x < y = x : (union < xt ys)
        || y < x = y : (union < xs yt)
        || t     = x : (union < xt yt)))

-----