[antlr-interest] Using @init and @after to populate an object with children

Les Bell lesbell at lesbell.com.au
Tue Sep 11 19:53:01 PDT 2012


I'm currently working on a DSL for implementation of computational trust
decisions in e-commerce transactions. The semantic model is, at base, a
state machine in which two agents step through the states, exchanging
messages which represent a contract between the two.

My simple DSL lets me write scripts with fragments like these:

state shopping
  on adReceived -> offering, sendOffer
end

which means that when in state 'shopping', if an adReceived message is
received, transition to state 'offering' and during the transition, send
an offer message.

The transitions are nested within states, and there will often be
multiple transitions in each state.

The problem I have is that construction of the state machine when the
script is parsed logically requires the State objects to be created
first, and then Transition objects added to them. But, of course, the
parser reads ahead and gets to the embedded transition rules, creating
the Transitions, before the state rule gets a chance to create a State.
The way I've solved this is - in skeletal form - as follows:

stateDec
    scope {
      ArrayList<Transition> at;
    }
    @init {
      $stateDec::at = new ArrayList<Transition>();
    }
    @after{
      // This was used for debugging
      System.out.println("at has " + $stateDec::at.size() + " members");
    }
    : 'state' ID (transition {$stateDec::at.add($transition.t);})* 'end'
    {
      State s = tt.getState($ID.text);  // If it didn't exist before, it
will be created.
      for (int i = 0; i < $stateDec::at.size(); i++ )
        s.addTransition($stateDec::at.get(i));
    } // End of action
    ;

and the transition rule looks like this (similarly processing its list
of commands):

transition returns [Transition t]
  scope {
    ArrayList<Command> ac;
  }
  @init {
    $transition::ac = new ArrayList<Command>();
  }
  : 'on' eventid (conditional {$transition::gc = $conditional.tree; })?
'->' ID (','! commandid {$transition::ac.add($commandid.command); })*
  { ... } ;

This seems a little ugly to me, but it works (as far as I've tested,
which isn't far yet). Have I overlooked a more obvious and natural way
do what I need? Also, would it be better to place the code that adds
children to the newly created object in the @after action?

Best,

--- Les Bell
[+61 2 9451 1144]
[http://www.lesbell.com.au]


More information about the antlr-interest mailing list