利用Antlr开发状态机

阅读更多
Antlr 不用多介绍了,只想说此乃神器也~~~

进入正题,首先是Antlr 定义的语法:

grammar StateMachine;

options {
output=AST;
ASTLabelType=CommonTree;
}

tokens {
RULE_ROOT;
STATE_DECLARATION;
CASE_CLAUSE;
CASE_DECLARATION;
}

@header {package compiler.statemachine;}
@lexer::header {package compiler.statemachine;}



ruleRoot
:
stateDeclaration* EOF
->^(RULE_ROOT stateDeclaration*)
;

stateDeclaration
:
Identifier '{' caseDeclaration* '}' ';'?
->^(STATE_DECLARATION Identifier ^(CASE_CLAUSE caseDeclaration*))
;

caseDeclaration
:
Identifier '=>' Identifier ';'
->^(CASE_DECLARATION Identifier+)
;

Identifier
:
('A'..'Z'|'a'..'z'|'_')('A'..'Z'|'a'..'z'|'0'..'9'|'_')*
;

COMMENT
:
'//' ~('\n'|'\r')* '\r'? ('\n'|EOF) {$channel=HIDDEN;}
    |
    '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS
:
(' '|'\t'|'\r'|'\u000C'|'\n') {$channel=HIDDEN;}
;



从语法定义中可以看出,我们使用时候需要输入的格式为

状态{动作=>新状态}


比如我们有业务是,商务专员填写好报价单后,提交到招标经理,招标经理审批通过后,提交到大区经理。

现在来定义我们业务中所会用到的State 和Action 的枚举
package compiler.statemachine;
public enum RequestState {
	 UnInitialized,
	 CommercialApplying, // 商务申请报价单
	 BiddingManagerAuditing, //招标经理审批报价单
	 CDManagerAuditing //大区经理审批报价单
}

package compiler.statemachine;
public enum RequestAction {
	 CommercialCreate,  //商务专员创建报价单
	 CommercialModify,  //商务专员修改报价单
	 CommercialCommit,  //商务专员提交报价单
	 BiddingManagerModify, //招标经理修改报价单
	 BiddingManagerApprove //招标经理审批通过报价单
}



两个枚举根据实际业务可以自由修改,比如 招标经理拒绝报价单等


接下来是重头戏,如何解析由Antlr生成的抽象语法树!

先定义StateMachine 接口

package compiler.statemachine;

import java.util.Set;

public interface StateMachine {
	Set getStates() ;
	
	Set getActions() ;
	
	Set getValidActions(TState state);
	
	TState changeState(TState currentState, TAction action);
	
}


然后编写实现类

package compiler.statemachine;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.Tree;

public class StateMachineImpl, TAction extends Enum> implements StateMachine{

	private Class stateType;

    private Class actionType;
    
	private String rule;
	
	private Map> dict = new HashMap>();
	
	public Class getStateType() {
		return stateType;
	}

	public void setStateType(Class stateType) {
		this.stateType = stateType;
	}

	public Class getActionType() {
		return actionType;
	}

	public void setActionType(Class actionType) {
		this.actionType = actionType;
	}

	public String getRule() {
		return rule;
	}

	public void setRule(String rule) {
		this.rule = rule;
	}
	
	public StateMachineImpl(){
		
	}
	
	
	public StateMachineImpl(Class state,Class action){
		this.stateType = state;
		this.actionType = action;
	}

	public void complieRule(){

		StateMachineLexer lexer = new StateMachineLexer(new ANTLRStringStream(rule));
		CommonTokenStream tokens = new CommonTokenStream(lexer);
		StateMachineParser parser = new StateMachineParser(tokens);
		try {
			Tree ruleRootNode = (Tree)parser.ruleRoot().getTree();
			for(int i=0;i nestedDict = new HashMap();				
				dict.put(state, nestedDict);
				
				for(int ii=0;ii getStates() {
		
		return dict.keySet();
	}

	@Override
	public Set getActions() {
	    Set actionsSet = new HashSet();
	    for (Map map : dict.values()) {
	    	actionsSet.addAll(map.keySet());
		}	    	  
	  
	    return actionsSet;
	}

	@Override
	public Set getValidActions(TState state) {
		if(!dict.containsKey(state)){
			throw new  RuntimeException("State not in the system");
		}
		return dict.get(state).keySet();
	}

	@Override
	public TState changeState(TState currentState, TAction action) {
		if(!dict.containsKey(currentState)){
			throw new IllegalArgumentException();
		}
		
		Map rules = dict.get(currentState);
		
		TState returnState = rules.get(action);
	
		if(returnState==null){
			throw new UnsupportedOperationException();
		}
			
		return returnState;
	}


}



最主要的就是complieRule 方法
解析Antlr 生成的抽象语法树,把 状态{动作=>新状态}这样格式的字符串,转换为
Map> dict = new HashMap>()
这样的一个Map

最后编写测试类

package test.statemachine;
import java.util.Map;
import java.util.Set;

import compiler.statemachine.EnumerationStateMechineLocalObject;
import compiler.statemachine.RequestAction;
import compiler.statemachine.RequestState;
import compiler.statemachine.StateMachineImpl;

public class StateMachineTest {

	public static void main(String[] args) {
		StateMachineTest();
	}

	
	public static void StateMachineTest() {
		StateMachineImpl stateMachine = new StateMachineImpl();				
		stateMachine.setRule("UnInitialized { CommercialCreate => CommercialApplying;}  CommercialApplying {CommercialModify => CommercialApplying;CommercialCommit => BiddingManagerAuditing;BiddingManagerModify => CommercialApplying; BiddingManagerApprove => CDManagerAuditing; }");
		stateMachine.setStateType(RequestState.class);
		stateMachine.setActionType(RequestAction.class);
		
		stateMachine.complieRule();
		RequestState requestState = RequestState.CommercialApplying;
		
		Set currentActions = stateMachine.getValidActions(requestState);
		
		if(currentActions.contains(RequestAction.BiddingManagerApprove)){
			requestState = stateMachine.changeState(requestState, RequestAction.BiddingManagerApprove);
		}
		
		Set actions = stateMachine.getActions();
		
		for (RequestAction requestAction : actions) {
			System.out.println(requestAction);
		}
		System.out.println(requestState);
	}

}




从代码:
stateMachine.setRule("UnInitialized { CommercialCreate => CommercialApplying;}  CommercialApplying {CommercialModify => CommercialApplying;CommercialCommit => BiddingManagerAuditing;BiddingManagerModify => CommercialApplying; BiddingManagerApprove => CDManagerAuditing; }");

可以看出 输入字符串
"UnInitialized { CommercialCreate => CommercialApplying;}  CommercialApplying {CommercialModify => CommercialApplying;CommercialCommit => BiddingManagerAuditing;BiddingManagerModify => CommercialApplying; BiddingManagerApprove => CDManagerAuditing; }"

调用stateMachine.complieRule();

通过 stateMachine.getValidActions 得到 当前状态的报价单所对应的所有可以执行的Action

例如现在招标经理要将商务提交的报价单审批通过;

则通过Set currentActions = stateMachine.getValidActions(requestState);

得到所有能够执行的Action

通过if(currentActions.contains(RequestAction.BiddingManagerApprove)){
requestState = stateMachine.changeState(requestState, RequestAction.BiddingManagerApprove);
}

来改变报价单的状态从 RequestState requestState = RequestState.CommercialApplying;

报价单状态从,商务申请中变为,大区经理审批中 CDManagerAuditing

实际运用中结合Spring可以优化
StateMachineImpl stateMachine = new StateMachineImpl();

stateMachine.setStateType(RequestState.class);
stateMachine.setActionType(RequestAction.class);
stateMachine.complieRule();



你可能感兴趣的:(java,Antlr,StateMachine)