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

Jesse McGrew jmcgrew at gmail.com
Tue Sep 11 21:13:25 PDT 2012


Why not use embedded actions like so:

stateDec
    scope {
      ArrayList<Transition> at;
    }
    @init { State s = null; }
    : 'state' ID {s = tt.getState($ID.text);}
    (transition {s.addTransition($transition.t);})* 'end'
    ;

The variable "s" has to be declared in @init so it'll be in scope for
the whole method, but if you put the allocation in an action, you can
avoid creating objects during backtracking.

Jesse

On Tue, Sep 11, 2012 at 7:53 PM, Les Bell <lesbell at lesbell.com.au> wrote:
> 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]
>
> List: http://www.antlr.org/mailman/listinfo/antlr-interest
> Unsubscribe: http://www.antlr.org/mailman/options/antlr-interest/your-email-address


More information about the antlr-interest mailing list