+1  A: 

I haven't tried to analyze it in detail, but: "From or To expression enclosed in parentheses" starts to sound a lot like "context dependent", which recursive descent can't handle directly. To avoid context dependence you'll probably need a separate production for a From or To in parentheses vs. a From or To without the parens.

Edit: Though it may be too late to do any good, if my understanding of what you want to match is correct, I think I'd write it more like this:

Graph := 
       | List Sep Graph
       ;

Sep := "->"
     | "<-"
     ;

List :=
      | Value List
      ;

Value := Number 
      | Identifier 
      | String 
      | '(' Graph ')'
      ;

It's hard to be certain, but I think this should at least be close to matching (only) the inputs you want, and should make it reasonably easy to generate an AST that reflects the input correctly.

Jerry Coffin
Ah ha! Right you are. I'll try adding another production rule. Typically I don't use recursive descent because I don't like refactoring complex grammars, so this is something of a learning experience for me.
Jon Purdy
All set! Thanks for your help.
Jon Purdy