@members { StateMachineLoader helper; } eventList : 'events' event* 'end'; event : name=ID code=ID {helper.addEvent($name, $code);}; // ここの中カッコの中が組み込みトランザクション。 // helper.addEvent() が外部コード呼び出し。
組み込みトランザクションの魅力
組み込みトランザクションの面倒なところ
例:ミスグラントのコントローラ (JavaとAntlr)
@members { StateMachineLoader helper; } machine : eventList resetEventList commandList state*; eventList : 'events' event* 'end'; event : name=ID code=ID {helper.addEvent($name, $code);}; state : 'state' name=ID {helper.addState($name);} actionList[$name]? transition[$name]* 'end'; actionList [Token state] : 'actions' '{' actions+=ID* '}' {helper.addAction($state, $actions);} ; transition [Token sourceState] : trigger=ID '=>' target=ID {helper.addTransition($sourceState, $trigger, $target);}; resetEventList : 'resetEvents' resetEvent* 'end' ; resetEvent : name=ID {helper.addResetEvent($name);}; class StateMachineLoader { private Map<String, Event> events = new HashMap<String, Event>(); private Map<String, Command> commands = new HashMap<String, Command>(); private Map<String, State> states = new HashMap<String, State>(); private List<Event> resetEvents = new ArrayList<Event>(); void addEvent(Token name, Token code) { events.put(name.getText(), new Event(name.getText(), code.getText())); } public void addAction(Token state, List actions) { for (Token action : (Iterable<Token>) actions) getState(state).addAction(getCommand(action)); } private State getState(Token token) { return states.get(token.getText()); } public void addTransition(Token state, Token trigger, Token target) { getState(state).addTransition(getEvent(trigger), obtainState(target)); } private State obtainState(Token token) { String name = token.getText(); if (!states.containsKey(name)) states.put(name, new State(name)); return states.get(name); } public void addState(Token n) { obtainState(n); if (null == machine) machine = new StateMachine(getState(n)); } public void addResetEvent(Token name) { resetEvents.add(getEvent(name)); } public StateMachine run() { try { stateMachineLexer lexer = new stateMachineLexer(new ANTLRReaderStream(input)); stateMachineParser parser = new stateMachineParser(new CommonTokenStream(lexer)); parser.helper = this; parser.machine(); machine.addResetEvents(resetEvents.toArray(new Event[0])); return machine; } catch (IOException e) { throw new RuntimeException(e); } catch (RecognitionException e) { throw new RuntimeException(e); } } }
途中、まったく意味が通じないところがあった。
Most parser generators provide a facility to use Foreign Code, the only one I've used that doesn't is intended to work with Tree Construction.
英語がnativeやfluentでは無い人(つまり私)のために、もっと、plain English で記述して欲しいなぁ。