I wrote a quick PEG Parser for Julia with Packrat capabilities:

https://github.com/abeschneider/PEGParser

It's a first draft and needs a ton of work, testing, etc., but if this is 
of interest to anyone else, here is a quick description.

Grammars can be defined using most of the standard EBNF syntax. For 
example, a simple math grammar can be defined as:

@grammar mathgrammar begin

  start = expr
  number = r"([0-9]+)"
  expr = (term + op1 + expr) | term
  term = (factor + op2 + term) | factor
  factor = number | pfactor
  pfactor = ('(' + expr + ')')
  op1 = '+' | '-'
  op2 = '*' | '/'
end



To parse a string with the grammar:

(node, pos, error) = parse(mathgrammar, "5*(2-6)")

This will create an AST which can then be transformed to a value. Currently 
this is accomplished by doing:

math = Dict()

math["number"] = (node, children) -> float(node.value)
math["expr"] = (node, children) ->
    length(children) == 1 ? children : eval(Expr(:call, children[2], 
children[1], children[3]))
math["factor"] = (node, children) -> children
math["pfactor"] = (node, children) -> children[2]
math["term"] = (node, children) ->
    length(children) == 1 ? children : eval(Expr(:call, children[2], 
children[1], children[3]))
math["op1"] = (node, children) -> symbol(node.value)
math["op2"] = (node, children) -> symbol(node.value)


Ideally, I would like to simplify this to using multi-dispatch on symbols 
(see previous post), but for now this is the easiest way to define actions 
based on node attributes.

Finally, to transform the tree:

result = transform(math, node)  # will give the value of 20

Originally I was going to attach the transforms to the rules themselves 
(similiar to boost::spirit). However, there were two reasons for not doing 
this:

   1. To implement the packrat part of the parser, I needed to cache the 
   results which meant building an AST anyways
   2. It's nice to be apply to get different transforms for the same 
   grammar (e.g. you may want to transform the result into HTML, LaTeX, etc.)

The downside of the separation is that it adds some more complexity to the 
process.

Reply via email to