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,一经查实,立即删除!

相关文章

[渝粤教育] 西南科技大学 工程力学 在线考试复习资料

工程力学——在线考试复习资料 一、判断题 1.平面图形的静矩与坐标系无关。 2.弯矩图上的极值就是梁内最大的弯矩。 3.悬臂梁或外伸梁的自由端处弯矩必定为零。 4.弯矩图应画在梁受拉的一侧。 5.当挤压面为圆柱形侧面时&#xff0c;挤压面的计算面积按该圆柱侧面的正投影面…

appium的python教程_移动App Appium自动化测试教程Appium+Python 【2018年新】_IT教程网...

资源名称&#xff1a;移动App Appium自动化测试教程AppiumPython 【2018年新】资源目录&#xff1a;第一章&#xff1a;App自动化测试概述1-1 Appium自动化课程简介1-2 课程大纲1-3 移动设备操作系统兴亡简史1-4 移动App自动化测试兵器发展历程1-5 移动App自动化测试兵器发展历…

Derby数据库备份

抽象 我已经发布了许多有关Derby的博客&#xff1a; 同一主机上的多个Derby网络服务器 Apache Derby数据库用户和权限 与Maven和内存中Derby数据库的集成测试 这本不打算是一个系列。 但是多年来&#xff0c;我越来越多地使用Derby。 最近&#xff0c;我开始将Derby用作微服…

[渝粤教育] 西南科技大学 市场营销理论与实务 在线考试复习资料2021版(1)

市场营销理论与实务——在线考试复习资料2021版 一、单选题 1.处于市场不景气或原料.能源供应紧张时期,( )产品线反而能使总利润上升。 A.增加 B.扩充 C.延伸 D.缩减 答案:看左边查询 2.以高于价值的价格将新产品推入市场,然后…

[渝粤教育] 西南科技大学 建筑经济与企业管理 在线考试复习资料

建筑经济与企业管理——在线考试复习资料 一、单选题 1.某建筑公司预计今后5年中,每年末拿出50万元作为生产基金,将其投资生产预制构件,投资年利率为12%。到第五年末,该公司共得( )万元 A.305.3 B.317.64 C.320.7 D.330 2.某公司拟投资一个项目,预计建成后每年能获利50万元…

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

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

[渝粤教育] 西南科技大学 投资经济学 在线考试复习资料(1)

投资经济学——在线考试复习资料 一、单选题 1.投资决策是经济决策的重要组成部分,是选择和决定( )的过程 A.投资资金 B.投资行动方案 C.投资机会 D.投资目的 2.下面属于第三产业的行业是( ) A.制造业 B.建筑业 C.农业 D.商业 3.重视资金的( )是正确确定项目成本和收益的不可…

python写图片爬取软件_python抓取整个网站图片

Python分布式爬虫原理转载 permike 原文 Python分布式爬虫原理首先&#xff0c;我们先来看看&#xff0c;如果是人正常的行为&#xff0c;是如何获取网页内容的。(1)打开浏览器&#xff0c;输入URL&#xff0c;打开源网页(2)选取我们想要的内容&#xff0c;包括标题&#xff0c…

[渝粤教育] 西南科技大学 数据库应用 在线考试复习资料

数据库应用——在线考试复习资料 一、单选题 1.“表达式生成器”是用来书写什么的? A.代码 B.程序 C.表达式 D.数据库 2.在使用计算控件时,每个表示式前必须加上哪种运算符号? A. B. C.? D.* 3.以下属于非绑定控件的是哪一个? A.文本框 B.单选按钮 C.组合框 D.直线控件 …

[渝粤教育] 西南科技大学 机械制造装备及工艺 在线考试复习资料

机械制造装备及工艺——在线考试复习资料 一、单选题 1. 金属切削过程中,工件材料的塑性或韧性越高,切屑越不易折断,使切屑与前刀面间的摩擦增大,故切削力( ) A.变化不定 B.增大 C.增小 D.不变 2. 金属切削过程中,在温度很高时,接触面间切屑底层金属呈…

JBoss模块很烂,无法在JBoss 7下使用自定义Resteasy / JAX-RS

由于JBoss EAP 6.1 / AS 7.2.0是模块化的&#xff0c;并且您可以排除Webapp可见的模块&#xff0c;因此您希望可以轻松地忽略内置的JAX-RS实现&#xff08;Rest Easy 2.3.6&#xff09;并使用它。自定义的&#xff08;3.0.6&#xff09;。 但是&#xff0c;可悲的是&#xff0c…

cad怎么将图层后置_CAD中如何将某1个图层置于其他图层之上.doc

CAD中如何将某1个图层置于其他图层之上《CAD一千零一个技巧》图层管理17种用法 CAD具备强大的图层工具功能&#xff0c;统计一共有17种&#xff0c;这17种应用大大地满足了用户编辑图层的需求&#xff0c;而这17种图层工具的具体应用&#xff0c;你都会吗&#xff1f;?1、图层…

[渝粤教育] 西南科技大学 液压与气压传动 在线考试复习资料(1)

液压与气压传动——在线考试复习资料 一、单选题 1.柱塞泵与其它泵相比( )次 A.工作压力高 B.效率低 C.速度低 D.工作压力低 2.变量泵是( ) A.排量不可变 B.排量可变 C.压力可变 D.转速可变 3.卸荷回路是属于( ) A.压力控制回路 B.方向控制回路 C.加速控制回路 D.减速控制回路…

Eclipse GlassFish 5.1就在这里!

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

[渝粤教育] 西南科技大学 电器设备及维修 在线考试复习资料

电器设备及维修——在线考试复习资料 一、单选题 1.复合同步信号包括行同步信号和( )。 A.场同步信号 B.行消隐信号 C.场消隐信号 D.场均衡信号 2.高频头主要由输入回路,混频器,本振电路和( )组成 A.自动亮度调节电路 B.自动频率调节电路 C.同步检波器 D.高频放大器 3.…

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

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

[渝粤教育] 西南科技大学 畜牧概论 在线考试复习资料

畜牧概论——在线考试复习资料 一、单选题 1.色氨酸在动物体内可转变为下列那一种维生素。 A.烟酸 B.叶酸 C.泛酸 D.生物素 2.根据蛋白质中的平均蛋含量可知,1克氮能合成粗蛋白质多少克。 A.5.25 B.6.00 C.6.25 D.6.75 3.赖氨酸与下列那一种氨基酸之间存在颉抗作用。 A.精氨酸…

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

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

[渝粤教育] 西南科技大学 管理运筹学与系统分析 在线考试复习资料

管理运筹学与系统分析——在线考试复习资料 一、单选题 1.下列那种方法不适用于网络时间的计算( ) A.修正分配法 B.表格计算法 C.图上计算法 D.矩阵计算法 2.在运输方案中出现退化现象,是指数字格的数目( ) A.等于mn B.大于mn-1 C.小于mn-1 D.等于mn-1 3.一元线性回归模型预测…

[渝粤教育] 西南科技大学 网络程序设计 在线考试复习资料

网络程序设计——在线考试复习资料 一、单选题 1.Sng函数的作用是( )。 A.将字符串转换为日期 B.将字符串转换为长整型 C.将字符串转换为布尔型 D.将数值转换为单精度型 2.数据库常用的函数中,返回最小值的是( )。 A.OUNT B.MIN C.VG D.SUM 3.数据库常用的函数中,计算字段值的…