java 自定义语言 解析_【词法分析】自定义动态语言处理框架

本文介绍了如何使用Java实现自定义动态语言处理框架,包括词法分析和语法分析。通过解析SQL语句的示例,展示了词法分析器Lexer的角色,如提供词汇表和解析语言。同时,详细解释了语法分析器LanguageParse如何构建语法树,并通过访问者模式对语法树进行访问和操作。
摘要由CSDN通过智能技术生成

一、学习目的

项目研发过程中经常会需要将业务逻辑外置,需要将业务逻辑和代码分离。一般面对这样的需求有以下几种解决办法:

引入一个规则引擎,比如Drools。

利用java的javax.script.ScriptEngineManager调用javascript脚本。

利用antlr这样的开源项目定义自己的业务领域语言。

二、词法分析

把程序中的词法单元分为四类:标识符(分为关键字和一般标识符)、数字、特殊字符、空白(空格、Tab、回车换行等)

三、参考sql语句的词法分析和语法分析

Druid 的代码里,代表语法分析和词法分析的类分别是 SQLParser 和 Lexer。并且, Parser 拥有一个 Lexer。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classSQLParser {protected finalLexer lexer;protectedString dbType;publicSQLParser(String sql, String dbType){this(newLexer(sql), dbType);this.lexer.nextToken();

}publicSQLParser(String sql){this(sql, null);

}publicSQLParser(Lexer lexer){this(lexer, null);

}publicSQLParser(Lexer lexer, String dbType){this.lexer =lexer;this.dbType =dbType;

}

}

View Code

Lexer 作为词法分析器,必然拥有其词汇表,在Lexer里,以 Keywords 表示。

Keywords 实际上是 key 为单词,value 为 Token 的字典型结构,其中 Token 是单词的类型,比如说,“select” 的 Token 类型就是 Select Token,而 “abc” 的 Token 类型,则是标识符,也表示为 Identifier Token。

而 MySqlLexer 类,除了沿用其父类的 Keywords 外,自己还有自己的 Keywords。可以理解为 Lexer 所维护的关键字集合,是通用的;而 MySqlLexer 除了有通用的关键字集合,也有属于 MySQL 数据库 SQL 方言的关键字集合。

Parser 是 Lexer 的使用者,站在 Parser 的角度看,它会怎么去使用 Lexer,或者说,Lexer 应该具备怎样的功能,才能满足 Parser 的使用需求。

Lexer 应该具备一个函数,能让使用者命令它解析一个单词,并且 Lexer 还必须提供一个函数,供使用者获取 Lexer 上一次解析到的单词以及单词的类型。

在 Lexer 中,nextToken() 这个方法提供了第一个需求,只要被调用,它就按顺序从 SQL 语句的开头到结尾,解析出下一个单词;token() 方法,则返回了上一次解析的单词的 Token 类型,如果 Token 类型是标识符(Identifier),Lexer 还提供了一个 stringVal() 方法,让使用者能拿到标识符的值。

走进 Lexer 的 nextToken() 方法,可以发现它的代码充斥着 if 语句和 switch 语句,因为解析单词的时候,是一个字符一个字符地解析,这就意味着,这个方法每次扫描一个字符,都必须判断单词是否结束,应该用什么方式来验证这个单词等等。这个过程,就是一个状态机运作的过程,每解析到一个字符,都要判断当前的状态,以决定应该进入下一个什么状态。

四、自定义动态语言处理框架

1、抽象的对象及作用

词法分析器

=>提供词汇表

=>提供语言解析

语法分析器

=>提供语法解析

=>构建语法树

语法树

=>一条自然语言构造成的语法树

语法树访问器

=>对语法树进行访问

2、各个角色之间的关系的伪代码

词法分析器

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.spring.sxf.study.springtradedao.mysql.language;/*** 词法分析器

* 主要功能

* 1、提供词汇表

* 2、访问语句,提炼出词汇*/

public interfaceLexer {/*** 获取当前token

*@return

*/Token token();/*** 寻找下一个token*/

voidnextToken();/*** 获取被解析的语句

*@return

*/String getText();/*** 设置要被解析的语句*/

voidsetText(String text);

}packagecom.spring.sxf.study.springtradedao.mysql.language;/*** 词汇表

* 1、一般标识

* 2、语法关键词汇*/

public enumToken {

}

View Code

语法分析器

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.spring.sxf.study.springtradedao.mysql.language;importjava.util.ArrayList;importjava.util.List;/*** 语法解析器

* 主要功能

* 1、根据语法访问词法分析器,组织语法树*/

public classLanguageParse {/*** 根据词法分析器解析出语法树

*

*@paramlexer

*@return

*/Listparse(Lexer lexer){//解析SelectColumnNode

SelectColumnNode selectColumnNode=parseSelect(lexer);//解析FromTableNode

FromTableNode fromTableNode=parseFrom(lexer);//组装语法数

List nodes=new ArrayList<>();

nodes.add(newDefaultNode(selectColumnNode,fromTableNode));returnnodes;

}

SelectColumnNode parseSelect(Lexer lexer){//解析该子节点

return null;

}

FromTableNode parseFrom(Lexer lexer){//解析该子节点

return null;

}

}

View Code

语法树及语法树的节点

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.spring.sxf.study.springtradedao.mysql.language;/*** 语法树的节点

* 1、根据语法解析器解析出语法树

* 2、允许访问者进行访问*/

public interfaceNode {/*** 允许访问器访问语法树

*@paramvisitor*/

voidaccept(Visitor visitor);

}packagecom.spring.sxf.study.springtradedao.mysql.language;importjava.util.List;/*** 查询类名的节点*/

public abstract class SelectColumnNode extendsNodeImpl{/*** 获取查询的列名集合

*@return

*/

abstract ListgetColumns();

@Overridevoidaccept0(Visitor visitor) {//获取所有列名

visitor.visit(this);

}

}packagecom.spring.sxf.study.springtradedao.mysql.language;importjava.util.List;/*** 查询表名的节点*/

public abstract class FromTableNode extendsNodeImpl {/*** 获取查询的表名集合

*

*@return

*/

abstract ListgetTableName();

@Overridevoidaccept0(Visitor visitor) {

visitor.visit(this);

}

}packagecom.spring.sxf.study.springtradedao.mysql.language;/*** 模拟一个语法树

* 该语法树有两个子节点:SelectColumnNode和FromTableNode*/

public class DefaultNode extendsNodeImpl {privateSelectColumnNode selectColumnNode;privateFromTableNode fromTableNode;publicDefaultNode(SelectColumnNode selectColumnNode, FromTableNode fromTableNode) {this.selectColumnNode =selectColumnNode;this.fromTableNode =fromTableNode;

}

@Overridevoidaccept0(Visitor visitor) {//访问自身

visitor.visit(this);//访问孩子节点

selectColumnNode.accept(visitor);

fromTableNode.accept(visitor);

}

}

View Code

访问器

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.spring.sxf.study.springtradedao.mysql.language;importjava.util.List;/*** 模拟一个语法树访问器*/

public class DefaultNodeVisitor implementsVisitor {private ListselectCloumns;private ListtableNames;

@Overridepublic voidpreVisit(Node x) {//执行前置操作

}

@Overridepublic voidendVisit(Node x) {//执行后置操作

}

@Overridepublic voidvisit(SelectColumnNode selectColumnNode) {//解析列

this.selectCloumns =selectColumnNode.getColumns();

}

@Overridepublic voidvisit(FromTableNode fromTableNode) {//解析表名

this.tableNames =fromTableNode.getTableName();

}

@Overridepublic voidvisit(DefaultNode defaultNode) {//解析语法树根节点

}

ListgetCloumns() {return this.selectCloumns;

}

ListgetTableNames() {return this.tableNames;

}

}

View Code

代码示意

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.spring.sxf.study.springtradedao.mysql.language;importjava.util.List;/*** 模拟各个抽象对象之间的关系*/

public classTest {public static voidmain(String[] args) {//要被解析的自然语言

String text = "select a,b from t_order";//step1:建立词法分析器

Lexer lexer = newLexer() {

@OverridepublicToken token() {return null;

}

@Overridepublic voidnextToken() {

}

@OverridepublicString getText() {return null;

}

@Overridepublic voidsetText(String text) {

}

};

lexer.setText(text);//step2:建立语法分析器&并解析出语法树

LanguageParse languageParse=newLanguageParse();

List nodes=languageParse.parse(lexer);//step3:访问语法树,确认表名和列名

DefaultNodeVisitor visitor=newDefaultNodeVisitor();

nodes.get(0).accept(visitor);//获取列名

visitor.getCloumns();//获取表名

visitor.getTableNames();

}

}

View Code

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值