我记得应该在初中时候学习集合及集合的相关运算的概念,现在在看看下面的总结复习一下。
1、集合的含义:某些指定的对象集在一起就成为一个集合,其中每一个对象叫元素。
2、集合的中元素的三个特性: 1)元素的确定性; 2)元素的互异性;3)元素的无序性
列如:集合{1,4,7} 与{1,4,7,7}、{7,4,1}、{4,7,1}是等价的相同的集合
集合的定义其实就跟java中Set集合实现几乎是一样。
再看看下表中的集合 *** 作
*** 作 | 符号 | 例子 |
---|---|---|
并(union) | ∪ | {1, 2}∪{红色, 白色} = {1, 2, 红色, 白色} |
交(intersect) | ∩ | {1, 2}∩{红色, 白色} ={} {1, 2, 绿色}∩{红色, 白色, 绿色} = {绿色} |
差(subtract) | - | {1, 2}−{红色, 白色} = {1, 2} {1, 2, 绿色}−{红色, 白色, 绿色} = {1, 2} {1, 2} -{1,2, 白色} ={} |
示例: (A∩B)∩C = A∩(B∩C)
集合 *** 作运算的结果还是一个集合,并且还可以参与接下来的集合运算,这就有点类似函数递归调用的感觉。这就是这边文章的核心,我们要通过javacc实现一套集合函数,包括集合的运算(可以递归),通过这个脚步编写拔高自己在javacc语法定义及动作实现水平。
当然为了体现函数的定义及递归的特点,集合的 *** 作不在用数学上定义的符文(这类符号不好打出来)而是采用“函数名(参数1,参数2...)”方式体现。
例如:subtract(u3,intersect(union(u1,u2),u3))
集合的定义还是“{1,2,'red' }”方式体现。既然是脚步,那么变量赋值定义也是少不了的。我们就仿照python这类的脚步变量去搞,简单一些。
例如1: a = 1+5*(7-3)
例如2:u1 = {1,4,7+9,'red'}
语法分析在我总结的四则运算解析的那边文章里,提到了语法分析的方法是画语法解析树图。这次还是通过画图讲解。不过只画出集合定义以及集合 *** 作函数相关的解析树图,这一部分处理好就可以把这个棵子树合并到整个解析树中。这也是分治的思想。
集合定义语法树
集合里是有0到n元素e 构成的,元素e 又是有数字四则(也是语法树)或者 '字符串'(普通字符语法树) 构成的。所以就形成了上图的集合定义语法树图。
集合 *** 作函数语法树
funName:union、intersect、subtract
集合 *** 作函数的参数是至少2个set集合构成的,set集合有可以是集合定义树,或者是集合 *** 作(运算后的结果仍然是个集合),所以就形成了循环嵌套的语法树图。
看起来这个树跟之前的四则运算有点像,实现上是有区别的。四则运算 *** 作数和结果都是数字(double),但是集合 *** 作函数的参数set从图上看是两个不同的类型。考验抽象定义的能力到了,可以定义个名字叫算子(xxOperator)接口 ,集合的定义和集合 *** 作函数是该接口的实现类,那么就在形式上是同一的类型了。
好了核心点的分析就到此为止了,其他的赋值表达式定义等语法树相对比较简单,在此不在画图分析。
脚步语法实现 Zcode.jjoptions{
STATIC = false;
JDK_VERSION = "1.8";
}
PARSER_BEGIN(Zcode)
package com.javacc.zcode;
import com.javacc.zcode.*;
import com.javacc.zcode.operator.*;
import com.javacc.zcode.operator.bean.*;
import java.io.StringReader;
import java.util.*;
public class Zcode {
ZpContext zpContext;
public Zcode(String expr){
this(new StringReader(expr));
zpContext = new ZpContext();
}
}
PARSER_END(Zcode)
SKIP : { " " | "\t" | "\n" }
TOKEN : {
| "."
>
|
<#DIGITS :(["0"-"9"])+>
}
TOKEN : {
< LPAREN: "(" >
| < RPAREN: ")" >
| < LBPAREN: "{">
| < RBPAREN: "}">
| < ADD : "+" >
| < SUBTRACT : "-" >
| < MULTIPLY : "*" >
| < DIVIDE : "/" >
| < EQUALS : "=">
| < COMMA : ",">
| < SEMIC : ";">
| < SINGLE_QUOT : "'">
|< UNION : "UNION" | "union">
|< INTERSECT : "INTERSECT"| "intersect">
|< SET_SUB : "SUBTRACT" | "subtract">
|
|
}
TOKEN : { < EOL : "\n" | "\r" | "\r\n" > }
TOKEN : {
(|)*>
}
TOKEN : { < # LETTER : (["_",
"~",
"a"-"z","A"-"Z"])+ > }
//脚步解析入口
void parse():
{
}
{
(
LOOKAHEAD(2, )
assignExp() //赋值表达式
| printFunction() //打印函数
)+ //脚步中包含多条赋值表达和打印函数,每条都以“;”结尾 作为区分
}
//打印函数
void printFunction():
{
int flag;
//打印目标
Object target = null;
Token vt;
}
{
(
{flag=1;}
| {flag=2;}
)
(
vt = {target = zpContext.getVariable(vt.image);} //变量
| target = calc() //四则运算
| target = defineSets() //集合定义
| target = setOperFunciton() //集合运算函数
)
{
PrintOperator print = new PrintOperator(flag,target);
print.operator();
}
}
//赋值表达式
void assignExp():
{
Token t;
double v;
ZcOperator operator = null;
}
{
t=
(
v = calc() {zpContext.putVariable(t.image,v);}
| operator = setOperFunciton() {zpContext.putVariable(t.image,operator);}
| operator = defineSets() {zpContext.putVariable(t.image,operator);}
)
}
//集合定义:{element,element.....} 或者{}
ZcOperator defineSets():
{
Set data = new LinkedHashSet();
ZcResult elem = null;
}
{
(
elem = element() {data.add(elem.getData());}
(
elem = element() {data.add(elem.getData());}
)*
)*
{ return new SetOperator(data);}
}
//集合元素定义
ZcResult element():
{
Token t;
double v;
}
{
v = calc() {return new ZcResult(v);} //匹配数字四则
| t = {return new ZcResult(t.image);} //匹配'字符串'
}
//解析集合 *** 作函数
ZcOperator setOperFunciton():
{
int flag;
List pList = new ArrayList();
ZcOperator operator = null;
}
{
( {flag=1;}
| {flag =2;}
| {flag =3;}
)
operator = setOperBase() {pList.add(operator);} // *** 作集合
(
operator = setOperBase() {pList.add(operator);}
)+
{ return new SetFunctionOperator(flag,pList,zpContext); }
}
//集合
ZcOperator setOperBase():
{
ZcOperator operator = null;
Token t;
}
{
operator = defineSets() {return operator;} //集合定义
| t = { return zpContext.getVariable(t.image);} //集合赋值给的变量
| operator = setOperFunciton() {return operator;} //集合 *** 作函数
}
//解析一级树处理加减
double calc():
{
double left;
double right;
}
{
left = mutlOrDiv()
( right = mutlOrDiv() {left += right;}
| right = mutlOrDiv() {left = left - right;}
)*
{
return left;
}
}
//解析二级树处理乘除
double mutlOrDiv():
{
double left;
double right;
}
{
left = parseBase()
( right = parseBase() {left *= right ;}
| right = parseBase() {left = left/right;}
)*
{
return left;
}
}
//解析三级树
double parseBase() :
{
Token t = null;
double num;
}
{
t = {return Double.parseDouble(t.image);}
//处理括号里的四则
| num = calc() {return num;}
}
该语法文件是在四则运算基础进行的扩展的,其核心实现基本上与语法分析的思路基本是一致,不同的地方是增加对变量的解析支持,另外增加了赋值表达式、打印函数的解析等。
ZcOperator.java/**
* @description: 算子定义接口
*
*/
public interface ZcOperator {
/**
* 算子运算 *** 作
* @return ZcResult 返回结果
*/
ZcResult operator();
}
ZcResult.java
/**
* @description: 算子运算的结果类
*/
public class ZcResult {
private final T data;
public ZcResult(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
ZcVoid.java
/**
* @description: 无实际返回结果的算子结果类
*/
public class ZcVoid extends ZcResult{
private final static ZcVoid zcVoid = new ZcVoid();
public ZcVoid(ZcVoid data) {
super(data);
}
private ZcVoid(){
super(zcVoid);
}
@Override
public ZcVoid getData() {
throw new UnsupportedOperationException("ZcVoid Unsupported");
}
public static ZcVoid getInstance(){
return zcVoid;
}
}
SetOperator.java
/**
* @description: 集合定义算子
*/
public class SetOperator implements ZcOperator{
/**
* 结果集
*/
private ZcResult result;
public SetOperator(Set data){
result = new ZcResult(data);
}
public ZcResult operator() {
return result;
}
}
SetFunctionOperator.java
/**
* @description: 集合 *** 作函数算子
*/
public class SetFunctionOperator implements ZcOperator{
/**
* 函数名标记
*/
private final int flag;
/**
* 函数中的参数列表
*/
private List params;
/**
* 运算上下文
*/
private ZpContext context;
public SetFunctionOperator(int flag, List params, ZpContext context) {
this.flag = flag;
this.params = params;
this.context = context;
}
public ZcResult operator() {
List list = new ArrayList();
//先把参数列表中结果拿出来放到list数组中
for (ZcOperator op : params){
//从{e,...e}集合定义中获取
if(op instanceof SetOperator){
SetOperator setOperator = (SetOperator) op;
list.add(setOperator.operator().getData());
}
//从集合的 *** 作运算中获取结果
if(op instanceof SetFunctionOperator){
SetFunctionOperator sfp = (SetFunctionOperator) op;
//注意sfp.operator()会进行递归运算
list.add(sfp.operator().getData());
}
}
Set set = new LinkedHashSet();
//利用hutool工具包中集合工具进行集合运算 *** 作
switch (flag){
//进行union(并) *** 作
case 1:
if (list.size()>2){
set = CollUtil.unionDistinct(list.get(0),list.get(1),
list.subList(2,list.size()).toArray(new Set[0]));
}else {
set = CollUtil.unionDistinct(list.get(0),list.get(1));
}
break;
//进行intersection(交) *** 作
case 2:
if (list.size()>2){
set = CollUtil.intersectionDistinct(list.get(0),list.get(1),
list.subList(2,list.size()).toArray(new Set[0]));
}else {
set = CollUtil.intersectionDistinct(list.get(0),list.get(1));
}
break;
//进行subtract(差) *** 作
case 3:
set = (Set) CollUtil.subtract(list.get(0),list.get(1));
break;
}
return new ZcResult(set);
}
}
ZpContext.java
/**
* @description: 脚步解析上下文
*/
public class ZpContext {
protected ZpContext(){}
private Map context = new ConcurrentHashMap(256);
/**
* 是否存在变量名
* @param var 变量名
* @return
*/
public boolean existVariable(String var){
return context.containsKey(var);
}
/**
* 放置变量
* @param var 变量名
* @param data 变量值
*/
public void putVariable(String var,Object data){
context.put(var,new ZcResult(data));
}
/**
* 获取变量值
* @param var 变量名
* @return 返回的结果
*/
public T getVariable(String var){
ZcResult result = context.get(var);
//不存在的变量会抛错
if (null == result){
throw new IllegalArgumentException("不存在变量:"+var);
}
return (T) result.getData();
}
}
PrintOperator.java
/**
* @description: 打印函数
*/
public class PrintOperator implements ZcOperator{
/**
* 打印方式标记
*/
private int flag;
/**
* 打印目标
*/
private Object target;
public PrintOperator(int flag, Object target) {
this.flag = flag;
this.target = target;
}
public ZcResult operator() {
Object t = target ;
if(target instanceof ZcOperator){
ZcOperator zo = (ZcOperator) target;
t =zo.operator().getData();
}
switch (flag){
case 1:
System.out.print(t);
case 2:
System.out.println(t);
}
return ZcVoid.getInstance();
}
}
测试用例
public class ZcodeTest {
@Test
void test1() throws ParseException {
String prog =" a = 1+5*(7-3) ; \n"+
" println(a); \n"+
" u1 = {1,4,7+9}; \n"+
" u2 = {'red','yellow'}; \n"+
" u3 ={10+6,'red','ind'}; \n"+
" unionSet = union(u1,u2,u3); \n"+
" println(unionSet); \n"+
" interSet = intersect(union(u1,u2),u3); \n"+
" println(interSet); \n"+
" println(subtract(u3,intersect(union(u1,u2),u3)));";
Zcode zcode = new Zcode(prog);
zcode.parse();
}
}
执行结果
从测试用例上可以看出,脚步语法解析能力已经具备了编程语言的雏形。这也就是javacc、antlr这类语法解析器生成器独特魅力的地方。当然大家也可以在他们的官网上找到一些以javacc、antlr开发的编程语言的语法解析样例供大家学习。
上一篇:JAVACC使用总结(四):LOOKAHEAD解决语法选择冲突的利刃_IT不码农的博客-CSDN博客
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)