views:

197

answers:

2

I am trying to write an ANTLR parser rule that matches a list of things, and I want to write a parser action that can deal with each item in the list independently.

Some example input for these rules is:

$(A1 A2 A3)

I'd like this to result in an evaluator that contains a list of three MyIdentEvaluator objects -- one for each of A1, A2, and A3.

Here's a snippet of my grammar:

my_list returns [IEvaluator e]
    : { $e = new MyListEvaluator(); }
      '$'
      LPAREN
      op=my_ident+ { 
                     /* want to do something here for each 'my_ident'. */ 
                     /* the following seems to see only the 'A3' my_ident */
                     $e.Add($op.e);
                   }
      RPAREN
    ;

my_ident returns [IEvaluator e]
    : IDENT { $e = new MyIdentEvaluator($IDENT.text); }
    ;

I think my_ident is defined correctly, because I can see the three MyIdentEvaluators getting created as expected for my input string, but only the last my_ident ever gets added to the list (A3 in my example input).

How can I best treat each of these elements independently, either through a grammar change or a parser action change?

It also occurred to me that my vocabulary for these concepts is not what it should be, so if it looks like I'm misusing a term, I probably am.


EDIT in response to Wayne's comment:

I tried to use op+=my_ident+. In that case, the $op in my action becomes an IList (in C#) that contains Antlr.Runtime.Tree.CommonTree instances. It does give me one entry per matched token in $op, so I see my three matches, but I don't have the MyIdentEvaluator instances that I really want. I was hoping I could then find a rule attribute in the ANTLR docs that might help with this, but nothing seemed to help me get rid of this IList.


Result...

Based on chollida's answer, I ended up with this which works well:

my_list returns [IEvaluator e]
    : { $e = new MyListEvaluator(); }
      '$'
      LPAREN
      (op=my_ident    { $e.Add($op.e); } )+
      RPAREN
    ;

The Add method gets called for each match of my_ident.

+1  A: 

If I was writing this I'd split out the individual matching into a list pattern:

my_list returns [IEvaluator e]
: { $e = new MyListEvaluator(); }
  '$'
  LPAREN
  op=my_ident { $e.Add($op.e); }
  (opNext=my_ident { $e.Add($opNext.e); })*
  RPAREN
;


my_ident returns [IEvaluator e]
: IDENT { $e = new MyIdentEvaluator($IDENT.text); }
;

Here instead of using Antlr's built in + we do the iteration ourselves. We match the first item and add it to the list, then we match successive items and store them.

chollida
A: 
my_list returns [IEvaluator e]
  : '$' LPAREN ops+=my_ident+ RPAREN { e = new MyListEvaluator(list_ops); }
  ;

I'm doing something similar in Java and had to inspect the generated code to find that ANTLR3 generates a variables called "list_NAME" (where NAME=ops in this case) which is a list of all the sub-token rule return values. I imagine it's the same in C#, though I could be wrong. You would expect the variable to be called just "ops" but that variable will only ever contain the last matched rule value (in Java, at least).

JoelPM