antlr4 代码 语法树_使用ANTLR4,用于代码镜像和基于Web的DSL的Primefaces扩展

antlr4 代码 语法树

DSL是很酷的东西,但我不清楚它们有什么用。

然后我意识到它们对以下方面有好处:

  • 摆脱复杂的UI

意思是

  • 更快的做事方式

而已。 当我阅读此博客时,我得出了这个结论。

如果您的用户是技术人员,并且不惧怕类似SQL的语法处理方式,则DSL特别适合

  • 你有语法高亮
  • 你有代码补全

否则,DSL有点烂。

因此,我不得不向客户提出一些概念证明。 他有模糊的要求,要准确提取团队的需求并不容易(他们需要很多东西,而且他很忙),因此DSL可以在此过程中提供很多帮助,因为人们被迫在他们需要时才想清楚他们的需求面对一种语法(甚至很小的一种)。

因此,我采用了以下技术:

  • 用于代码镜像的JSF库Primefaces扩展
  • ANTLR4 (与ANTLR3相比有很大的改进,而且本书很棒)

不幸的是,我无法在两个工具中重复使用语法。 实际上,我找不到任何可以做到这一点的解决方案。 至少对于基于Web的JSF解决方案。 而且没有时间学习。 所以我不得不稍微改一下。

首先,我们需要语法。 ANTLR4比ANTLR3更好,因为现在接线代码是通过访问者和侦听器完成的。 语法内没有更多的Java代码。 那很棒,而且更容易使用。

所以你可以有一个这样的语法

grammar Grammar;
options
{language = Java;
}
@lexer::header {package parsers;
}@parser::header {package parsers;
}
eval     :     expr EOF;
expr    :    'JOB' (jobName)? type 'TARGET' targetList ('START' startExpr)?
startExpr   :    'AT' cronTerm|    'AFTER' timeAmount timeUnits;
timeAmount: INT;   
jobName: STRING;   
targetList: STRING (',' STRING)*;   
type    :    deleteUser|    createUser;deleteUser: opDelete userName;
createUser: opCreate userName;
opDelete: 'DELETE';
opCreate: 'CREATE';
userName: STRING;cronTerm: '!'? (INT | '-' | '/' | '*' | '>' | '<')+;timeUnits:    'MINUTES'|    'HOURS'|    'DAYS'|    'WEEKS'|    'MONTHS';WS  :   [ \t\r\n]+ -> skip;STRING:  '"' ( ESC_SEQ | ~('\\'|'"') )* '"';fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;fragment
ESC_SEQ:   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')|   UNICODE_ESC|   OCTAL_ESC;fragment
OCTAL_ESC:   '\\' ('0'..'3') ('0'..'7') ('0'..'7')|   '\\' ('0'..'7') ('0'..'7')|   '\\' ('0'..'7');fragment
UNICODE_ESC:   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT;ID  :    ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;INT :    '0'..'9'+;

要编译语法,请尝试

public static void main(String[] args) {String[] arg0 = {"-visitor","/pathto/Grammar.g4"};org.antlr.v4.Tool.main(arg0);}

然后,ANTLR将为您生成类。

在我们的例子中,我们想访问解析树并检索我们想要的值。 我们这样做扩展了生成的抽象类。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;import org.antlr.v4.runtime.tree.ErrorNode;import bsh.EvalError;
import bsh.Interpreter;public class MyLoader2 extends GrammarBaseVisitor<Void> {private String jobName,cronTerm,timeUnits,userName,jobType;private List<String> targetList;private boolean now,errorFound;private int timeAmount;   private Interpreter bsh = new Interpreter();private String eval(String s) throws EvaluationException{try {if (!s.startsWith("\"")){return s;}bsh.eval("String s="+s);return (String)bsh.eval("s");} catch (EvalError e) {throw new EvaluationException(s);}}@Overridepublic Void visitTimeAmount(TimeAmountContext ctx) {try{this.timeAmount = Integer.parseInt(ctx.getText());}catch(java.lang.NumberFormatException nfe){throw new InvalidTimeAmountException(ctx.getText());}return super.visitTimeAmount(ctx);}@Overridepublic Void visitUserName(UserNameContext ctx) {this.userName = eval(ctx.getText());return super.visitUserName(ctx);}@Overridepublic Void visitCronTerm(CronTermContext ctx) {this.cronTerm = eval(ctx.getText());return super.visitCronTerm(ctx);}@Overridepublic Void visitTimeUnits(TimeUnitsContext ctx) {this.timeUnits = ctx.getText();return super.visitTimeUnits(ctx);}@Overridepublic Void visitTargetList(TargetListContext ctx) {this.targetList = toStringList(ctx.getText());return super.visitTargetList(ctx);}@Overridepublic Void visitJobName(JobNameContext ctx) {this.jobName = eval(ctx.getText());return super.visitJobName(ctx);}@Overridepublic Void visitOpCreate(OpCreateContext ctx) {this.jobType = ctx.getText();return super.visitOpCreate(ctx);}@Overridepublic Void visitOpDelete(OpDeleteContext ctx) {this.jobType = ctx.getText();return super.visitOpDelete(ctx);}private List<String> toStringList(String text) {List<String> l = new ArrayList<String>();StringTokenizer st = new StringTokenizer(text," ,");while(st.hasMoreElements()){l.add(eval(st.nextToken()));}return l;}private Map<String, String> toMapList(String text) throws InvalidItemsException, InvalidKeyvalException {Map<String, String> m = new HashMap<String, String>();if (text == null || text.trim().length() == 0){return m;}String[] items = text.split(",");if (items.length == 0){throw new InvalidItemsException();}for(String item:items){String[] keyval = item.split("=");if (keyval.length == 2){m.put(keyval[0], keyval[1]);}else{throw new InvalidKeyvalException(keyval.length);}}return m;}public String getJobName() {return jobName;}public String getCronTerm() {return cronTerm;}public String getTimeUnits() {return timeUnits;}public String getUserName() {return userName;}public String getJobType() {return jobType;}public List<String> getTargetList() {return targetList;}public boolean isNow() {return now;}public int getTimeAmount() {return timeAmount;}@Overridepublic Void visitOpNow(OpNowContext ctx) {this.now = ctx.getText().equals("NOW");return super.visitOpNow(ctx);}public boolean isErrorFound() {return errorFound;}@Overridepublic Void visitErrorNode(ErrorNode node) {this.errorFound = true;return super.visitErrorNode(node);}
}

请注意, beanshell解释器用于将“ xyz”之类的字符串评估为xyz。 这对于其中包含转义引号和字符的字符串特别有用。

因此,您有了语法和visiter / loader bean,然后我们可以对其进行测试:

private static MyLoader getLoader(String str){ANTLRInputStream input = new ANTLRInputStream(str);GrammarLexer lexer = new GrammarLexer(input);CommonTokenStream tokens = new CommonTokenStream(lexer);GrammarParser parser = new GrammarParser(tokens);ParseTree tree = parser.eval();MyLoader loader = new MyLoader();loader.visit(tree);return loader;
}public static void main(String[] args){MyLoader loader = getLoader("JOB \"jobName\" CREATE \"myuser\" TARGET \"site1\",\"site2\" START AFTER 1 DAY");System.out.println(loader.getJobName());System.out.println(loader.getJobType());
}

大。 现在是黑客。 Code Mirror支持自定义语法,但JSF Primefaces扩展中不存在 。 因此,我打开了resources-codemirror-1.2.0.jar,打开了/META-INF/resources/primefaces-extensions/codemirror/mode/modes.js文件,对其进行了格式化 (以便我可以阅读),然后我刚刚选择了最简单的语言作为我的新自定义sintax荧光笔!

我改名了

(...)
}, "xml"), CodeMirror.defineMIME("text/x-markdown", "markdown"), CodeMirror.defineMode("mylanguage", function (e) {
(...)var t = e.indentUnit,n, i = r(["site", "type", "targetList"]),s = r(["AT","AFTER","CREATE","MINUTES","HOURS","TARGET","MONTHS","JOB","DAYS","DELETE","START","WEEKS" ]),
(...)
}), CodeMirror.defineMIME("text/x-mylanguage", "mylanguage"), CodeMirror.defineMode("ntriples", function () {(...)

那些在“ s = r”中用大写字母表示的标记是将被突出显示的标记,而在“ i = r”中的那些标记则是将被突出显示的标记。 为什么我们都想要? 因为第二种类型是“占位符”,我的意思是,我们将它们用于自动填充内容。

好,那么您的JSF xhtml页面将如下所示

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:f="http://java.sun.com/jsf/core"xmlns:h="http://java.sun.com/jsf/html"xmlns:ui="http://java.sun.com/jsf/facelets"xmlns:p="http://primefaces.org/ui"xmlns:pe="http://primefaces.org/ui/extensions"><h:body>
<h:form id="form">
<pe:codeMirrorid="codeMirror"style="width:600px;" mode="myLanguage" widgetVar="myCodeMirror" theme="eclipse"value="#{myMB.script}"lineNumbers="true"             completeMethod="#{myMB.complete}" extraKeys="{ 'Ctrl-Space': function(cm) { PF('myCodeMirror').complete(); }}"/> 
<p:commandButton value="Verify" action="#{myMB.verify}" />
(...)

现在,我们需要自动完成功能。 这是无聊的部分。 您必须手动完成大部分的完成工作,因为没有上下文信息(请记住,我没有时间学习……),所以快速而肮脏的方式是这样的

in myMBpublic List<String> complete(final CompleteEvent event) {try {return this.myEJB.complete(event.getToken());} catch (Exception e) {jsfUtilEJB.addErrorMessage(e,"Could not complete");return null;}} in myEJBprivate static final String    SITE    = "site_";
public List<String> complete(String token) throws Exception {if (token == null || token.trim().length() == 0){return null;}else{List<String> suggestions = new ArrayList<String>();switch(token){//first search variablescase "targetlist":for(String v:TARGETS){suggestions.add(v);   }break;case "site":List<Site> allSites = this.baseService.getSiteDAO().getAll();for(Site s:allSites){suggestions.add("\""+SITE+s.getName()+"\"");}break;case "type":suggestions.add("DELETE \"userName\"");suggestions.add("CREATE \"userName\"");break;case "AT":suggestions.add("AT \"cronExpression\"");suggestions.add("AT \"0 * * * * * * *\"");break;case "AFTER":for(int a:AMOUNTS){for(String u:UNITS){if (a == 1){suggestions.add("AFTER"+" "+a+" "+u);}else{suggestions.add("AFTER"+" "+a+" "+u+"S");}}}break;case "TARGET":for(String v:TARGETS){suggestions.add("TARGET "+v+"");   }break;case "JOB":suggestions.add("JOB \"jobName\" \ntype \nTARGET targetlist \nSTART");break;case "START":suggestions.add("START AT \"cronExpression\"");suggestions.add("START AT \"0 * * * * * * *\"");for(int a:AMOUNTS){for(String u:UNITS){if (a == 1){suggestions.add("START AFTER"+" "+a+" "+u);}else{suggestions.add("START AFTER"+" "+a+" "+u+"S");}}}suggestions.add("START NOW");break;case "DELETE":suggestions.add("DELETE \"userName\"");break;case "CREATE":suggestions.add("CREATE \"userName\"");break;default:if (token.startsWith(SITE)){List<Site> matchedSites = this.baseService.getSiteDAO().getByPattern(token.substring(SITE.length())+"*");for(Site s:matchedSites){suggestions.add("\""+SITE+s.getName()+"\"");}}else{//then search substringsfor(String kw:KEYWORDS){if (kw.toLowerCase().startsWith(token.toLowerCase())){suggestions.add(kw);}}}}//end switch//remove dups and sortSet<String> ts = new TreeSet<String>(suggestions);           return new ArrayList<String>(ts);}
}private static final int[] AMOUNTS = {1,5,10};
private static final String[] UNITS = {"MINUTE","HOUR","DAY","WEEK","MONTH"};
private static final String[] TARGETS = {"site"};/** KEYWORDS are basic suggestions*/
private static final String[] KEYWORDS = {"AT","AFTER","CREATE","MINUTES","HOURS","TARGET","MONTHS","JOB","DAYS","DELETE","START","WEEKS"};

因此,关键字的自动填充内容将仅向您显示字段和更多关键字,而“占位符”(还记得jar中的codemirror javascript中的小写关键字吗?)是从数据库中检索到的动态值(用于实际值)完成的。 另外,您可以使用部分字符串来检索以子字符串开头的那些字符串,如下所示:

屏幕截图

当然,在JPA中类似模式的搜索可以这样执行:

public abstract class GenericDAO<E> {protected EntityManager entityManager;private Class<E> clazz;private EntityType<E> pClass;@SuppressWarnings("unchecked")public GenericDAO(EntityManager entityManager) {this.entityManager = entityManager;ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();this.clazz = (Class<E>) genericSuperclass.getActualTypeArguments()[0];EntityManagerFactory emf = this.entityManager.getEntityManagerFactory();Metamodel metamodel = emf.getMetamodel();this.pClass = metamodel.entity(clazz);}public List<E> getByPattern(String pattern) {pattern = pattern.replace("?", "_").replace("*", "%");CriteriaBuilder cb = entityManager.getCriteriaBuilder();CriteriaQuery<E> q = cb.createQuery(clazz);Root<E> entity = q.from(clazz);SingularAttribute<E, String> singularAttribute = (SingularAttribute<E, String>) pClass.getDeclaredSingularAttribute(getNameableField(clazz));Path<String> path = entity.get(singularAttribute);q.where(cb.like(path, pattern));q.select(entity);TypedQuery<E> tq = entityManager.createQuery(q);List<E> all = tq.getResultList();return all;}private String getNameableField(Class<E> clazz) {for(Field f : clazz.getDeclaredFields()) {for(Annotation a : f.getAnnotations()) {if(a.annotationType() == Nameable.class) {return f.getName();}}}return null;}
(...)

其中Nameable是您的实体类的注释:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Nameable {
}

用它来注释实体类中的单个列,即String。 像这样:

@Entity
@Table(uniqueConstraints=@UniqueConstraint(columnNames={"name"}))
public class Site implements Serializable {/****/private static final long serialVersionUID = 8008732613898597654L;@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;@Nameable@Column(nullable=false)private String name;
(...)

当然,“验证”按钮只是获取您的脚本并将其推入加载器。

参考:来自Leo's Notepad博客的JCG合作伙伴 Leonardo Shikida 使用ANTLR4,用于代码镜像的Primefaces扩展和基于Web的DSL玩。

翻译自: https://www.javacodegeeks.com/2014/01/playing-with-antlr4-primefaces-extensions-for-code-mirror-and-web-based-dsls.html

antlr4 代码 语法树

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/344185.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cnn 一维时序数据_蚂蚁集团智能监控的时序异常检测:基于 CNN 神经网络的异常检测...

1背景在蚂蚁集团智能监控领域&#xff0c;时序异常检测是极重要一环&#xff0c;异常检测落地中&#xff0c;业务方参考业界标准输出 Metrics 指标数据&#xff0c;监控不同业务、应用、接口、集群的各项指标&#xff0c;包含 Metrics 指标(总量、失败量、耗时等)和系统服务指标…

Eclipse GlassFish 5.1就在这里!

Eclipse GlassFish 5.1的发布是Jakarta EE的重要里程碑&#xff01; 首先&#xff0c;这证实了Oracle提供的GlassFish源代码可以在Eclipse Infrastructure上构建和组装。 第二&#xff0c; 通过通过Java EE 8兼容性测试&#xff0c;它可以验证所贡献的代码是否符合Java EE 8…

标签蛋白_His标签蛋白镍柱纯化后总有一条杂带怎么办?

小明His标签蛋白镍柱纯化有杂带怎么办啊汇研生物——His标签蛋白纯化填料家簇1.样品本身的的属性&#xff0c;His蛋白容易被体系中的蛋白酶降解时&#xff0c;此时就要在样品中加入蛋白酶抑制剂。避免在纯化过程中His蛋白被降解&#xff0c;呈现出纯化后纯度下降。2.His蛋白和其…

bootstrap 树形表格渲染慢_bootstrap table轻松实现数据表格

在使用bootstrap table时可能在很多时候回用的表格来显示数据&#xff0c;如果自己写那肯定没问题&#xff0c;但是数据展示出来就麻烦多了&#xff0c;然而bootstrap table 封装了一套完善的数据表格组件&#xff0c;把从后台请求的数据很容易就展示出来了&#xff0c;bootstr…

ssm如何支持热部署_Java 调式、热部署、JVM 背后的支持者 Java Agent

我们平时写 Java Agent 的机会确实不多&#xff0c;也可以说几乎用不着。但其实我们一直在用它&#xff0c;而且接触的机会非常多。下面这些技术都使用了 Java Agent 技术&#xff0c;看一下你就知道为什么了。-各个 Java IDE 的调试功能&#xff0c;例如 eclipse、IntelliJ &a…

war3必须安装的游戏组件_在单独的WAR组件中对SPA资源和API实现进行分区

war3必须安装的游戏组件单页应用程序正Swift吸引人们的注意力&#xff0c;以实现基于Web的丰富&#xff0c;健壮和移动友好的应用程序。 从本质上讲&#xff0c;这需要更改应用程序体系结构&#xff0c;在该体系结构中&#xff0c;整个应用程序用户界面都是使用JavaScript来实现…

matlab 矩阵jocobi迭代_高校MATLAB被禁用,掀起中国本土软件脆弱的冰山一角

近日哈工大、哈工程高校被美国禁止用正版的MATLAB软件&#xff0c;此消息一出可谓使得全体用过MATLAB的工作者为之震撼。因为少了这款软件&#xff0c;无异于缺失了有力的左膀右臂&#xff0c;如何才能游刃有余地遨游在科研和工作领域呢&#xff1f;然而对于外行人却不知道这款…

controll层跳转页面_java web开发中的各种层

java后端开发前&#xff0c;还是应该将各种层划分好&#xff0c;知道各自的作用&#xff0c;今天做一下总结。Dao层、Entity层、Service层、Controller层、view层1、Dao层(持久层、数据访问层)功能&#xff1a;只负责与数据库的数据进行交互&#xff0c;dao层是在Mybatis框架下…

图像的灰度级数越多越好_MATLAB-数字图像处理 图像直方图归一化

图像直方图归一化图像直方图概念&#xff1a;图像直方图是反映一个图像像素分布的统计表&#xff0c;其实横坐标代表了图像像素的种类&#xff0c;可以是灰度的&#xff0c;也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。图像是由像…

JDK 13:什么是AggressiveOpts?

JVM 11中已弃用Java VM标志-XX:AggressiveOpts [请参见JDK-8199777和JDK-8199778 ]“因为其行为是不明确的。” JDK-8199778的“问题”部分进一步说明了&#xff08;我添加了重点 &#xff09;&#xff1a; AggressiveOpts已被用作实现各种实验性能功能的包罗万象的方法&#…

擦地机器人修理_自带眼睛还有嘴,喷水式擦地机器人效果实测

小时候家里大扫除时&#xff0c;我最喜欢抢着扫把扫地&#xff0c;因为扫地相对比较轻松&#xff0c;快速扫完灰尘和垃圾就能跑出去玩。而擦地板相比扫地就麻烦多了&#xff0c;大面积的地板需要蹲下来一块一块擦&#xff0c;还要来回清洗擦布&#xff0c;现在父母年龄大了&…

pv实现前趋图_Excel 数据透视图实现简易交互式数据面板

美国Ebay公司成立于1995年的圣何塞&#xff0c;是一家可让全球民众上网买卖物品的线上拍卖及购物网站。本文将结合Ebay&#xff08;某类体育用品的&#xff09;在线拍卖数据&#xff0c;主要使用Excel数据透视表为工具&#xff0c;来实现简易的交互式数据面板以求对数据进行可视…

input不可编辑属性_谁不喜欢图文并茂呢:基于多模态信息的属性抽取

0. 前言最近做属性抽取&#xff0c;并且基于多模态信息&#xff08;文本图片&#xff09;那种&#xff0c;然后发现了一个比较经典的论文“Multimodal Attribute Extraction”。正好就顺着这个论文的思路&#xff0c;捋一下这个任务&#xff0c;复现一下&#xff0c;再记录一下…

HDMI高清光端机产品介绍

HDMI高清光端机对视频音频发布等起到传输作用&#xff0c;HDMI光端机由发送器和接收器组成&#xff0c;能通过单根光纤把计算机主机的音频&#xff0c;视频&#xff0c;USB延长到远端&#xff0c;用户可以在远端实时收听到电脑主机的图像和声音&#xff0c;并使用电脑控制。接下…

全局变量求平均分最高分最低分_想去江苏读大学,2021届山东考生需要多少分?...

点击链接查看详情&#xff1a;https://mp.weixin.qq.com/s/A1-e97_D4jbC_BRJtPIN2A​mp.weixin.qq.com江苏省2020年在山东普通批次本科招生66所院校。1027个专业&#xff1b;共4310人&#xff0c;最低分南通理工学院的船舶与海洋工程专业&#xff0c;464分&#xff0c;位次2437…

Thymeleaf的Spring数据

介绍 今天&#xff0c;我将讨论更具体的问题。 这次没有设计模式或算法&#xff1a;-)。 我们并不总是从头开始设计软件组件。 通常&#xff0c;我们必须尝试使现有软件组件协同工作。 Spring Boot是Java世界上最好的免费软件之一。 它解决了Spring的许多配置问题。 它非常灵活…

如何有效维护PDH光端机的常见故障?

众所周知&#xff0c;在PDH光端机的使用过程中&#xff0c;出现的故障可分为永久性故障和间断性故障。而永久性故障是指反映告警一直保持&#xff1b;间断性故障则是指故障时有时无&#xff0c;有时还可自动恢复。但无论是哪种故障&#xff0c;都与传输网有着密不可分的关系。接…

转为字符数组_数组的20种常用的方法?

1.shift 删除数组中的第一个元素2.pop 删除数组中的最后一个元素3.unshift 增加元素在数组的前面4.push 增加元素在数组的后面5.map 循环&#xff0c;并且返回新的数组6.forEach 循环&#xff0c;遍历7.filter 过滤&#xff0c;筛选出数组中的满足条件的&#xff0c;并且返回新…

Profibus-DP光端机产品功能特点及技术参数详解

Profibus DP总线光端机&#xff0c;符合Profibus DP协议&#xff0c;采用大规模FPGA设计&#xff0c;采用独创技术&#xff0c;可同时支持1路Profibus-DP到光纤中继&#xff0c;通信速率0-12Mpbs。支持多种光纤网络拓扑结构&#xff1a;点对点通讯、链型网络、星型网络及冗余环…

jenkins编译java_在Window上使用Jenkins自动发布Java工件

jenkins编译java这篇文章将展示如何使用Jenkins Continuous Integration自动执行Java Web应用程序&#xff08;使用MYSQL DB和基于Hibernate ORM在基于REST的Jersey2 Spring环境中开发的学生申请应用程序&#xff09;的发布过程-上载发布工件到发布存储库。 如上一篇文章《在Wi…