利用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<TState, TAction> {
Set<TState> getStates() ;

Set<TAction> getActions() ;

Set<TAction> 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<TState extends Enum<TState>, TAction extends Enum<TAction>> implements StateMachine<TState, TAction>{

private Class<TState> stateType;

private Class<TAction> actionType;

private String rule;

private Map<TState,Map<TAction,TState>> dict = new HashMap<TState,Map<TAction,TState>>();

public Class<TState> getStateType() {
return stateType;
}

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

public Class<TAction> getActionType() {
return actionType;
}

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

public String getRule() {
return rule;
}

public void setRule(String rule) {
this.rule = rule;
}

public StateMachineImpl(){

}


public StateMachineImpl(Class<TState> state,Class<TAction> 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<ruleRootNode.getChildCount();i++){

Tree stateDeclarationNode = ruleRootNode.getChild(i);
String stateText = stateDeclarationNode.getChild(0).getText();
TState state;
state = (TState) Enum.valueOf(this.stateType, stateText);
System.out.println(state.getClass());
Map<TAction,TState> nestedDict = new HashMap<TAction,TState>();
dict.put(state, nestedDict);

for(int ii=0;ii<stateDeclarationNode.getChildCount();ii++){
Tree caseClauseNode = stateDeclarationNode.getChild(ii);
for(int iii=0;iii<caseClauseNode.getChildCount();iii++){
Tree caseDeclarationNode = caseClauseNode.getChild(iii);
String actionText = caseDeclarationNode.getChild(0).getText();
String targetStateText = caseDeclarationNode.getChild(1).getText();
TAction action;
TState targetState;

action = (TAction) Enum.valueOf(this.actionType, actionText);
targetState = (TState) Enum.valueOf(this.stateType, targetStateText);

nestedDict.put(action, targetState);
}

}

}

} catch (RecognitionException e) {
e.printStackTrace();
}


}

@Override
public Set<TState> getStates() {

return dict.keySet();
}

@Override
public Set<TAction> getActions() {
Set<TAction> actionsSet = new HashSet<TAction>();
for (Map<TAction, TState> map : dict.values()) {
actionsSet.addAll(map.keySet());
}

return actionsSet;
}

@Override
public Set<TAction> 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<TAction,TState> rules = dict.get(currentState);

TState returnState = rules.get(action);

if(returnState==null){
throw new UnsupportedOperationException();
}

return returnState;
}


}



最主要的就是complieRule 方法
解析Antlr 生成的抽象语法树,把 状态{动作=>新状态}这样格式的字符串,转换为
Map<TState,Map<TAction,TState>> dict = new HashMap<TState,Map<TAction,TState>>()
这样的一个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<RequestState, RequestAction> stateMachine = new StateMachineImpl<RequestState, RequestAction>();
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<RequestAction> currentActions = stateMachine.getValidActions(requestState);

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

Set<RequestAction> 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<RequestAction> currentActions = stateMachine.getValidActions(requestState);

得到所有能够执行的Action

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

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

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

实际运用中结合Spring可以优化
StateMachineImpl<RequestState, RequestAction> stateMachine = new StateMachineImpl<RequestState, RequestAction>();

stateMachine.setStateType(RequestState.class);
stateMachine.setActionType(RequestAction.class);
stateMachine.complieRule();
【Antlr】Antlr 解析 DOT 格式 任意的由双引号包围的字符序列。 阅读详情

相关推荐

Python 解析器开发:PLY 与 ANTLR 案例剖析

Python 解析器开发:PLY 与 ANTLR 案例剖析

s13596191285的博客 176

ANTLR学习(二):ANTLR入门项目

文章目录前言一、项目简介二、ANTLR工具、运行库以及自动生成的代码三、将生成的语法分析器与Java程序集成四、构建一个语言类应用程序 前言 通过一个入门项目学习到: 一些ANTLR语法的语义元素定义 ANTLR根据语法自动生成代码的机制 如何讲自动生成的语法分析器和Java程序集成 如何使用语法分析树监听器辨析一个代码翻译工具 一、项目简介 构造一个语法,它为C语言或其继承者Java语法的一个很小的自己,我们将识别包括花括号或者嵌套的花括号的一些整数,例如 {1,2,3}和{1,{2,3},4}

weixin_52224421的博客 3320

用HFSS复现经典论文:从零搭建带孔缝屏蔽箱体模型(附完整建模步骤与避坑指南)

本文详细介绍了如何使用HFSS电磁仿真软件复现经典论文中的带孔缝屏蔽箱体模型,包括从零搭建模型、设置激励与边界条件、求解优化及结果验证的全过程。特别提供了建模中的布尔运算陷阱、激励设置技巧等实操难点的避坑指南,帮助工程师和学生深入理解电磁屏蔽效能研究。

weixin_30530339的博客 157

ANTLR4权威指南 - 第6章 尝试一些实际中的语法

第6章 尝试一些实际中的语法 在前一章,我们学习了通用词法结构和语法结构,并学习了如何用ANTLR的语法来表述这些结构。现在,是时候把我们学到的这些用来构建一些现实世界中的语法了。我们的主要目标是,怎样通过筛选引用手册,样例输入文件和现有的非ANTLR语法来构建一个完整语法。这一章,我们要实现五种语言,难度依次递增。现在,你不需要将它们全部都实现了,挑一个你最喜欢的实现,当你在实践过程中遇到问

NullPointerException 8325

MT4-EA自动化交易研究笔记(2022-04-22)

自从接触到mt4的EA自动化交易,更让我这个10多年的老程序员看到了曙光,目前来看也确实出了一点成果,只是是否能稳定盈利有待时间的考验,所以开此专栏,一来做做记录与分析,更好的优化我的EA,二来也希望能与更多的高手交流,以完善我的交易系统

t35254056的博客 2291

Jenkins Job DSL:用代码管理CI/CD配置的实践指南

Jenkins 是持续集成(CI)领域的经典开源平台,其核心价值在于自动化构建与交付流程。然而传统 UI 配置方式导致配置不可版本化、难以复现、审计困难,严重制约团队规模化协作效率。Job DSL 作为一种声明式配置即代码(IaC)方案,通过 Groovy 脚本驱动 Jenkins 内部 API,实现 Job、View、Folder 等资源的程序化创建与维护,天然支持 Git 版本控制、权限审计与环境一致性保障。它不替代 Pipeline,而是与其协同构成‘流程定义’与‘基础设施定义’双轨体系,显著提升 C

weixin_33744141的博客 518

Antlr4的使用简介

有很多生成解析器/编译器的工具,帮你来实现自定义的语言(DSL)。 yacc Yet Another Compiler Compiler jacc just another compiler compiler fro Java, ANTLR ANother Tool for Language Recognition 下面主要介绍的是Antlr。 Antlr的作者是 Terence Parr ,...

凌晨港口 1万+

如何快速学习 PHP 编程:从入门到实战的高效路径

PHP高效学习路线摘要:4-8周掌握Web开发核心技能。阶段1(1周)搭建XAMPP/MAMP环境,掌握基础语法和变量处理;阶段2(2周)重点学习表单处理、会话管理和PDO数据库操作(防SQL注入);阶段3(2-3周)实战开发个人博客等小项目。关键原则:边学边练(每个知识点配3-5个案例)、优先掌握Web刚需技能(HTTP请求、数据库、动态页面)、善用官方手册。避坑点:密码必须加密、SQL使用预处理、统一UTF-8编码。建议每天2-3小时实操,通过项目驱动学习,快速形成开发能力。

2501_94233638的博客 1387

我们如何使用 ANTLR4 构建 SQL 自动完成框架

如果您有兴趣,请继续关注未来的文章,我们将深入探讨完整的实现,包括如何使用基于 ANTLR4 的自动完成核心、特定于语法的处理,以及如何与。在研究了市场上主流的 SQL 客户端后,我们发现,虽然它们在简单的查询中表现良好,但在面对更复杂的 SQL 语句时,它们往往会遇到困难。对于解析器,如果输入字符串有效,它将构造并返回一个解析树(或抽象语法树,AST),它根据语法表示输入的语法结构。这是 ANTLR4 带来的卓越功能,也是它提供的关键优势之一——能够为跨各种 SQL 方言的自动完成提供可扩展的解决方案。

allway2的博客 585

DSP复习笔记(5)——外部接口模块XINTF

【注意】 1. 芯片型号:TMS320F28335 2. 适用于NJUSTEO李彧晟老师课程 3. 参考资料:《TMS320F28335 DSP原理、开发及应用》 4. 对应PPT第二章 5. 本章内容较多而且较为重要,请结合PPT一起复习

BerenCamlost的博客 1万+

SAP 关于替代料物料混用问题处理方案简介

电子料很多都是需要进行替代的,并且需要考虑当A物料库存不足时,需要考虑B物料的库存来满足需求,当需求不满足的时候也需要考虑物料的价格因素,同时考虑价格低的物料进行采购。3、还遇到过比较奇葩的处理替代料的解决方案就是将SAP系统中的需求数据用接口的方式全部传输到外围系统,同时还将所有物料的库存信息都通过接口的方式传输到外围系统中,然后通过外围系统进行替代料逻辑的处理,然后在回写回SAP更改BOM中的优先级,然后在重新下单,貌似解决了替代料的问题,但是好像又没有解决。时间:2024-01-27。

我小时候很黑的博客 2349

Amazon States Language (ASL) ANTLR4 语法解析指南:从 JSON 状态机到可执行解析器

Amazon States Language(ASL)是定义 AWS Step Functions 状态机的 JSON 描述语言,本仓库中的 `amazon-states-language` 模块提供了一套基于 ANTLR v4 的完整词法与语法规则([ASLLexer.g4](https://link.gitcode.com/i/3bb8331c029e2fca2a2d6b59401d54ab)

gitblog_00837的博客 200

模式分类识别 | TCN时间卷积神经网络多特征分类预测(Matlab完整程序)

模式分类识别 | TCN时间卷积神经网络多特征分类预测(Matlab完整程序)

前程算法屋的博客 748

深入antlr4ts源码:探索TypeScript目标运行时的内部工作原理

antlr4ts是ANTLR 4的TypeScript/JavaScript目标运行时,为开发者提供了在TypeScript应用中实现高效语法解析的能力。本文将带你深入antlr4ts的源码结构,理解其核心组件如何协同工作,以及如何为TypeScript环境优化语法解析流程。 ## 核心架构概览:antlr4ts的模块化设计 antlr4ts采用分层架构设计,将语法解析过程分解为多个职责明确的

gitblog_00421的博客 290

迫零均衡前与迫零均衡后眼图对比附Matlab代码

迫零均衡(Decision Feedback Equalization,DFE)是一种常用的数字通信技术,用于抑制信号传输中的多径干扰。迫零均衡(Decision Feedback Equalization,DFE)是一种常用的数字通信技术,用于抑制信号传输中的多径干扰。眼图是一种常用的信号质量评估工具,通过绘制接收到的信号在时域上的波形,可以直观地观察到噪声、失真和干扰等问题。眼图是一种常用的信号质量评估工具,通过绘制接收到的信号在时域上的波形,可以直观地观察到噪声、失真和干扰等问题。

ByteSparkX的博客 459

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

【antlr4】使用antlr4构造我的语法树

编译器的前端和后端。前端指的是编译器对程序代码的分析和理解。前端阶段只与语言的语法有关,而和目标机器无关。后端则是生成目标机器的目标代码有关。第一节说说编译器的前端技术。编译器将一般会将词法和语法解析器分开实现。

九师兄 690

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

ANTLR 权威参考 目录部分(TODO)

  前言   为什么要有一个彻底的新版本ANTLR   谁看这本书   书里有什么  I 介绍ANTLR和计算机语言翻译  1 1.1 蓝图   1.2 一个模拟迷宫   1.3 安装ANTLR   1.4 执行 ANTLR,调用识别器   1.5 语法开发环境--ANTLRWorks  2 计算机语言属性    2.1 使用状态机生成语句   2.2 生成复杂语言的需求   2.3 语句的树结构...

邢立军的技术专栏 173

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

java odata filter_用antlr解析odata filter条件表达式

这篇文章分享如何用antlr解析odata filter条件表达式。我最早接触antlr,是在刚开始工作后不久,那次需要用antlr实现一个功能:把gemfire的OQL(object query language)翻译成SQL语句,以便进行数据库操作。其实,简单讲,antlr就是一个非常方便的词法分析和语法分析的类库,基于这个类库,可以很容易的实现很多场景,比如计算器算术表达式的解析、各种编程语...

weixin_35926485的博客 687

Antlr(DSL)

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33696822的博客 385

ANTLR文本解析工具

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34376986的博客 651

219. 使用ANTLR构建解析器:从语法规则到高效解析的实现

本文详细介绍了如何使用ANTLR构建高效解析器,从语法规则定义到最终实现。内容涵盖ANTLR开发环境搭建、语法文件核心要素解析、解析器代码生成与集成,以及错误处理和性能优化技巧。通过实战案例(如JSON解析器)演示了ANTLR在构建领域特定语言(DSL)和复杂文本解析任务中的应用,帮助开发者快速掌握这一强大的解析器生成工具。

c8d9e0f1的博客 418

用ANTLR实现表达式词法和语法分析器

ANTLR(ANother Tool for Language Recognition)作为一款强大的解析器生成器,能根据文法文件自动生成词法、语法分析器,并支持多种目标语言(Java、Python、C++等)。本文将通过一个完整的表达式解析示例,深入剖析ANTLR的工作原理,并展示如何用它构建一个可用的计算器。的方式,将词法分析、语法分析和树遍历完全自动化,让开发者专注于业务逻辑(如求值、编译、转换)。,ANTLR会尝试匹配INT规则,直到遇到非数字字符才停止,然后回退到正确的token边界。

kI17G82Wi的博客 181

grammars-v4 中的 GDScript ANTLR4 语法实现:从 Godot EBNF 到可运行的词法/语法分析器

本篇文章基于 grammars-v4 仓库中的 [gdscript/README.md](https://link.gitcode.com/i/2f12869effceed0dd1949934bdfd9efa) 及其同目录下的完整 ANTLR4 实现,深入讲解 GDScript 语言的语法文件结构、缩进敏感词法分析、顶层声明与语句/表达式文法设计。读完本文,你将掌握 GDScript 官方 EBN

gitblog_00466的博客 374

ANTLR4实战:从零开始构建一个JSON解析器(附完整代码)

本文详细介绍了如何使用ANTLR4从零开始构建一个功能完整的JSON解析器。内容涵盖环境搭建、语法规则设计、代码生成与集成,并提供了完整的访问者模式实现代码。通过实战案例,帮助开发者掌握ANTLR4的核心应用,高效解决复杂数据格式的解析需求。

weixin_29300931的博客 442

Oracle MySQL ANTLR4 语法(MySQL Grammar for ANTLR v4):架构解析与实战使用指南

Oracle 的 MySQL ANTLR4 语法(`sql/mysql/Oracle/original/`)是为 MySQL 8.0 及以上版本打造的完整 ANTLR4 语法集,它既能解析 DDL/DML 全量语句,又通过"服务器版本 + SQL 模式"的双重运行时参数实现了灵活、正确的解析。本文基于该语法的官方 README 与仓库源码,为你拆解它的来源、解析机制、支撑基类(`MySQLBase

gitblog_00790的博客 243
上一篇: Java 动态代理
下一篇: Hibernate 自定义方言
sorta
博客等级 码龄18年 0粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值