解释器
解释器(英语:Interpreter),又译为直译器,是一种电脑程序,能够把高级编程语言一行一行直接转译运行。解释器不会一次把整个程序转译出来,只像一位“中间人”,每次运行程序时都要先转成另一种语言再作运行,因此解释器的程序运行速度比较缓慢。它每转译一行程序叙述就立刻运行,然后再转译下一行,再运行,如此不停地进行下去。
例如 JavaScript,在浏览器中就是用解释器进行处理运行,还有很多,这里就不一一举例。
目的
写这个解释器的目的的?就是为了方便游戏对象操作,我们都知道,一个游戏对象,有着很多的属性,如果开发者想要开发一个新玩法,就必须更改其模型,然而,这样来说是不现实的,如果新的玩法需要记录的数据只是一次性的,即领个礼包什么的,获得只是这个新玩法自带的,那我们更改模型这样的不对了,所以,我想写一个解释器,用来进行这方面数据的处理。
第一步: 表达式计算
思考一下,简单的加减乘除实现都很简单,那么,如果进行可扩展的呢?如果里面可以写变量呢?
package util;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.util.Pair;
/**
*
* @author lol
*/
public final class NumberGet {
private Map<String, Map<String, Object>> pro;
public NumberGet(Map<String, Object> u) {
pro = new HashMap();
pro.put("u", u);
}
public NumberGet(Map<String, Object> u, Map<String, Object> o) {
pro = new HashMap();
pro.put("u", u);
pro.put("o", o);
}
public NumberGet() {
pro = new HashMap();
}
public void setPro(Map<String, Map<String, Object>> pro) {
this.pro = pro;
}
public Object operation(String str) throws OperationException {
if (str.charAt(0) == '#') {
return str.substring(1);
} else {
return (int) Double.parseDouble(operation(str, 0).getValue().toString());
}
}
// 获取属性值
private Pair getNumOfV(String str, int index) throws OperationException {
String tempStr = new String();
int i;
char t;
String owner = ""; // 属性所有者
for (i = index; i < str.length(); i++) {
t = str.charAt(i);
if (t == '.') {
i++;
break;
}
owner += t;
}
// System.out.println("归属(NumberGet.65):" + owner);
for (; i < str.length(); i++) {
t = str.charAt(i);
if (t == 'v' && i < str.length() && str.charAt(i + 1) == '(') {
Pair p = getNumOfV(str, i + 2);
i = Integer.parseInt(p.getKey().toString());
tempStr += p.getValue().toString();
} else if (Character.isLetterOrDigit(t) || t == '_') {
tempStr += t;
} else if (t == ')') {
break;
} else if (t == '(') {
throw new OperationException("小括号不匹配---( " + str.substring(0, i) + " )");
} else {
throw new OperationException("只能是字符数字和下划线('_')---( " + str.substring(0, i) + " )");
}
}
if (i == str.length()) {
throw new OperationException("未找到匹配的右花括号---( " + str.substring(0, i) + " )");
}
Map<String, Object> own = pro.get(owner);
if (own == null) {
pro.put(owner, new HashMap());
own = pro.get(owner);
}
Object o = own.get(tempStr);
if (o == null) {
pro.get(owner).put(tempStr, "0");
o = pro.get(owner).get(tempStr);
}
return new Pair(i, (int) Double.parseDouble(o.toString()));
}
// 获取属性值
private Pair getNum(String str, int index) throws OperationException {
String tempStr = new String();
int i;
char t;
String owner = ""; // 属性所有者
for (i = index; i < str.length(); i++) {
t = str.charAt(i);
if (t == '.') {
i++;
break;
}
owner += t;
}
// System.out.println("归属(NumberGet.112):" + owner);
for (; i < str.length(); i++) {
t = str.charAt(i);
if (t == 'v' && i < str.length() && str.charAt(i + 1) == '(') {
Pair p = getNumOfV(str, i + 2);
i = Integer.parseInt(p.getKey().toString());
tempStr += p.getValue().toString();
} else if (Character.isLetterOrDigit(t) || t == '_') {
tempStr += t;
} else if (t == '}') {
break;
} else if (t == '{') {
throw new OperationException("花括号不匹配---( " + str.substring(0, i) + " )");
} else {
throw new OperationException("只能是字符数字和下划线('_')---( " + str.substring(0, i) + " )");
}
}
if (i == str.length()) {
throw new OperationException("未找到匹配的右花括号---( " + str.substring(0, i) + " )");
}
Map<String, Object> own = pro.get(owner);
if (own == null) {
pro.put(owner, new HashMap());
own = pro.get(owner);
}
Object o = own.get(tempStr);
if (o == null) {
pro.get(owner).put(tempStr, "0");
o = pro.get(owner).get(tempStr);
}
return new Pair(i, Double.parseDouble(o.toString()));
}
// 获取属性值,不存在花括号
private Pair getNumWithoutLR(String str, int index) throws OperationException {
int i = index;
char t;
int length = str.length();
char[] chars = str.toCharArray();
String leftStr = new String();
for (; i < length; i++) {
if (!Character.isLetterOrDigit(chars[i]) && chars[i] != '.') {
break;
}
leftStr += chars[i];
}
String owner = "t"; // 属性所有者
if (leftStr.indexOf('.') != -1) {
owner = leftStr.substring(0, leftStr.indexOf('.'));
leftStr = leftStr.substring(leftStr.indexOf('.') + 1);
}
Map<String, Object> own = pro.get(owner);
if (own == null) {
pro.put(owner, new HashMap());
own = pro.get(owner);
}
Object o = own.get(leftStr);
if (o == null) {
pro.get(owner).put(leftStr, "0");
o = pro.get(owner).get(leftStr);
}
return new Pair(i, Double.parseDouble(o.toString()));
}
// 计算二个数
private double getNum(double a, Object opr, double b) throws OperationException {
//Thread.sleep(1);
//System.out.println("\t\t" + a + opr.toString() + b);
if (opr.equals("==")) {
if (a == b) {
return 1;
} else {
return 0;
}
} else if (opr.equals("!=")) {
if (a == b) {
return 0;
} else {
return 1;
}
} else if (opr.equals(">=")) {
if (a >= b) {
return 1;
} else {
return 0;
}
} else if (opr.equals("<=")) {
if (a <= b) {
return 1;
} else {
return 0;
}
} else if (opr.equals("&&")) {
if (a != 0 && b != 0) {
return 1;
} else {
return 0;
}
} else if (opr.equals("||")) {
if (a != 0 || b != 0) {
return 1;
} else {
return 0;
}
} else if (opr.equals('>')) {
if (a > b) {
return 1;
} else {
return 0;
}
} else if (opr.equals('<')) {
if (a < b) {
return 1;
} else {
return 0;
}
} else if (opr.equals('+')) {
return a + b;
} else if (opr.equals('-')) {
return a - b;
} else if (opr.equals('*')) {
return a * b;
} else if (opr.equals('/')) {
return a / b;
} else if (opr.equals('%')) {
return a % b;
} else if (opr.equals('=')) {
return a;
} else {
throw new OperationException("非法运算符---( " + opr + " )");
}
}
// 获取上一个数字和运算符
private void getNum(Stack s, double num) throws OperationException {
if (!s.empty()) {
Object op = s.pop();
Object leftNum = s.pop();
num = getNum(Double.parseDouble(leftNum.toString()), op, num);
}
s.add(num);
}
// 是否为运算符
private boolean isOp(char t) {
if (t == '!' || t == '=' || t == '<' || t == '>' || t == '+' || t == '-' || t == '/' || t == '*' || t == '%') {
return true;
} else {
return false;
}
}
// 计算
private Pair operation(String str, int index) throws OperationException {
Stack s = new Stack();
double num = 0, num3 = 10, temp;
boolean flag = false;
boolean isTrue = true;
int i;
char t;
for (i = index; i < str.length(); i++) {
t = str.charAt(i);
if (t == '(') {
Pair p = operation(str, i + 1);
if (isTrue) {
num = Double.parseDouble(p.getValue().toString());
}
i = Integer.parseInt(p.getKey().toString());
} else if (t == ')') {
break;
} else if (t == '?') {
if (!s.empty()) {
Object op = s.pop();
Object leftNum = s.pop();
num = getNum(Double.parseDouble(leftNum.toString()), op, num);
}
if (num == 0) {
isTrue = false;
}
num = 0;
num3 = 10;
flag = false;
} else if (t == ':') {
if (!isTrue) {
num = 0;
num3 = 10;
flag = false;
isTrue = true;
} else {
isTrue = false;
}
} else if (!isTrue) {
// doNothing
} else if (t == '{') {
Pair p = getNum(str, i + 1);
num = Double.parseDouble(p.getValue().toString());
i = Integer.parseInt(p.getKey().toString());
} else if (t == '.') {
if (!flag) {
flag = true;
} else {
throw new OperationException("非法小数点---( " + str.substring(0, i + 1) + " )");
}
} else if (Character.isDigit(t)) {
if (!flag) {
num *= 10;
num += t - '0';
} else {
temp = t - '0';
temp /= num3;
num3 *= 10;
num += temp;
}
} else if (isOp(t)) {
if ((i + 1) < str.length() && isOp(str.charAt(i + 1))) {
getNum(s, num);
s.add(t + String.valueOf(str.charAt(i + 1)));
i++;
} else {
getNum(s, num);
s.add(t);
}
num = 0;
num3 = 10;
flag = false;
} else if (t == '|') {
if (str.charAt(i + 1) != t) {
throw new OperationException("非法条件运算符---( " + str.substring(0, i + 1) + " )");
}
getNum(s, num);
s.add("||");
Pair p = operationOfAndOr(str, i + 2);
System.out.println(p);
num = Double.parseDouble(p.getValue().toString());
i = Integer.parseInt(p.getKey().toString());
} else if (t == '&') {
if (str.charAt(i + 1) != t) {
throw new OperationException("非法条件运算符---( " + str.substring(0, i + 1) + " )");
}
getNum(s, num);
s.add("&&");
Pair p = operationOfAndOr(str, i + 2);
num = Double.parseDouble(p.getValue().toString());
i = Integer.parseInt(p.getKey().toString());
} else if (Character.isLetter(t)){
Pair p = getNumWithoutLR(str, i);
num = Double.parseDouble(p.getValue().toString());
i = Integer.parseInt(p.getKey().toString());
i--;
}
}
while (s.size() > 1) {
Object op = s.pop();
Object leftNum = s.pop();
num = getNum(Double.parseDouble(leftNum.toString()), op, num);
}
return new Pair(i, num);
}
// 计算&& 和 ||
private Pair operationOfAndOr(String str, int index) throws OperationException {
Stack s = new Stack();
double num = 0, num3 = 10, temp;
boolean flag = false;
boolean isTrue = true;
int i;
char t;
for (i = index; i < str.length(); i++) {
t = str.charAt(i);
if (t == '(') {
Pair p = operation(str, i + 1);
if (isTrue) {
num = Double.parseDouble(p.getValue().toString());
}
i = Integer.parseInt(p.getKey().toString());
} else if (t == ')') {
break;
} else if (t == '?') {
if (!s.empty()) {
Object op = s.pop();
Object leftNum = s.pop();
num = getNum(Double.parseDouble(leftNum.toString()), op, num);
}
if (num == 0) {
isTrue = false;
}
num = 0;
num3 = 10;
flag = false;
} else if (t == ':') {
if (!isTrue) {
num = 0;
num3 = 10;
flag = false;
isTrue = true;
} else {
isTrue = false;
}
} else if (!isTrue) {
// doNothing
} else if (t == '{') {
Pair p = getNum(str, i + 1);
num = Double.parseDouble(p.getValue().toString());
i = Integer.parseInt(p.getKey().toString());
} else if (t == '.') {
if (!flag) {
flag = true;
} else {
throw new OperationException("非法小数点---( " + str.substring(0, i + 1) + " )");
}
} else if (Character.isDigit(t)) {
if (!flag) {
num *= 10;
num += t - '0';
} else {
temp = t - '0';
temp /= num3;
num3 *= 10;
num += temp;
}
} else if (isOp(t)) {
if ((i + 1) < str.length() && isOp(str.charAt(i + 1))) {
getNum(s, num);
s.add(t + String.valueOf(str.charAt(i + 1)));
i++;
} else {
getNum(s, num);
s.add(t);
}
num = 0;
num3 = 10;
flag = false;
} else if (Character.isLetter(t)){
Pair p = getNumWithoutLR(str, i);
num = Double.parseDouble(p.getValue().toString());
i = Integer.parseInt(p.getKey().toString());
i--;
} else if (t == '|' || t == '&' || t == '?' || t == ':') {
i--;
break;
}
}
while (s.size() > 1) {
Object op = s.pop();
Object leftNum = s.pop();
num = getNum(Double.parseDouble(leftNum.toString()), op, num);
}
return new Pair(i, num);
}
public static void main(String[] args) {
Map<String, Object> u = new HashMap();
u.put("gjl", 100);
u.put("temp_100_lvl", 6);
Map<String, Object> o = new HashMap();
o.put("fyl", 100);
NumberGet ng = new NumberGet(u, o);
try {
System.out.println(ng.operation("u.gjl+u.gjl"));
} catch (OperationException ex) {
ex.printStackTrace();
}
}
}
我去除了乘除法的优先级,优先级由括号进行控制,上面就可以实现我们所需要的表达式计算了。
第二步: 多行处理(赋值、条件、循环)
这里我们用上面的表达式计算进行计算处理,这里其实还是很简单的,我们只需要利用Java写好的if for while即可。
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.util.Pair;
/**
*
* @author lol
*/
public class GC {
private Map<String, Map<String, Object>> pro;
static Map<String, Integer> keyword = null;
public GC() {
if (keyword == null) {
keyword = new HashMap();
keyword.put("for", 3);
keyword.put("while", 2);
keyword.put("if", 1);
}
pro = new HashMap();
}
// 去除空格
private int clearSpace(char[] chars, int start, int end) {
int length = end;
int i = start;
// 去空格
for (; i < length; i++) {
if (chars[i] != ' ' && chars[i] != '\t' && chars[i] != '\n' && chars[i] != '\r') {
break;
}
}
return i;
}
// 获得左边操作语句
private Pair getLeftStr(char[] chars, int start, int end) {
int length = end;
int i = start;
String leftStr = new String();
for (; i < length; i++) {
if (!Character.isLetterOrDigit(chars[i]) && chars[i] != '.') {
break;
}
leftStr += chars[i];
}
Pair p = new Pair(i, leftStr);
return p;
}
// 获得右边操作语句
private Pair getRightStr(char[] chars, int start, int end) {
int length = end;
int i = start;
String rightStr = new String();
for (; i < length; i++) {
if (chars[i] == ';') {
break;
}
rightStr += chars[i];
}
Pair p = new Pair(i, rightStr);
return p;
}
// 获得左右括号匹配
private Pair getLeftAndRight(char[] chars, int start, int end, char cLeft, char cRight) {
// System.out.println("括号匹配:" + cLeft + "|" + cRight + "=====" + String.valueOf(chars).substring(start, end));
int length = end;
int i = start;
int lefts = 0;
int left = -1;
int right = -1;
for (int j = i; j < length; j++) {
if (chars[j] == cLeft) {
if (lefts == 0) {
left = j;
}
lefts++;
} else if (chars[j] == cRight) {
if (lefts == 1) {
right = j;
break;
} else {
lefts--;
}
}
}
return new Pair(left, right);
}
// 处理单行赋值运算
private Pair getValue(String line, int start, int end) throws OperationException {
char[] chars = line.toCharArray();
int length = end;
int i = start;
// 去空格
i = clearSpace(chars, i, length);
Pair p;
String leftStr = new String(); // 左边操作对象
String centerStr = new String(); // 中间操作符
String rightStr = new String(); // 左边操作对象
// 检测左边操作对象
p = getLeftStr(chars, i, length);
leftStr = (String) p.getValue();
i = (int) p.getKey();
//System.out.println("左边操作对象为: " + leftStr);
// 去空格
i = clearSpace(chars, i, length);
// 检测中间操作符
for (; i < length; i++) {
if (Character.isLetterOrDigit(chars[i]) || chars[i] == ' ') {
break;
}
centerStr += chars[i];
}
//System.out.println("中间操作符为: " + centerStr);
// 去空格
i = clearSpace(chars, i, length);
// 右边操作对象
p = getRightStr(chars, i, length);
rightStr = (String) p.getValue();
i = (int) p.getKey();
// System.out.println("右边的操作对象为: " + rightStr);
String own = "t";
if (leftStr.indexOf('.') != -1) {
own = leftStr.substring(0, leftStr.indexOf('.'));
leftStr = leftStr.substring(leftStr.indexOf('.') + 1);
}
Map<String, Object> t = pro.get(own);
if (t == null) {
pro.put(own, new HashMap());
}
t = pro.get(own);
NumberGet numberGet = new NumberGet();
numberGet.setPro(pro); // 将数据导入
if ("=".equals(centerStr)) { // 计算等式
t.put(leftStr, numberGet.operation(rightStr));
}
p = new Pair(i, t.get(leftStr));
return p;
}
// 执行if 和 else
private int runIFAndElse(String line, int start, int end) throws OperationException {
char[] chars = line.toCharArray();
int length = end;
int i = start;
Pair p;
i = clearSpace(chars, i, length);
p = getLeftAndRight(chars, i, length, '(', ')');
int left = (int) p.getKey();
int right = (int) p.getValue();
// System.out.println("if 的 左右括号为:" + left + "," + right);
i = clearSpace(chars, right + 1, length);
// 寻找if范围
p = getLeftAndRight(chars, i, length, '{', '}');
int tStartOfIf = (int) p.getKey();
int tEndOfIf = (int) p.getValue();
i = clearSpace(chars, tEndOfIf + 1, length);
p = getLeftStr(chars, i, length);
String tStr = (String) p.getValue();
int ti = (int) p.getKey();
int tStartOfElse = -1;
int tEndOfElse = -1;
// 寻找else范围
if ("else".equals(tStr)) {
i = clearSpace(chars, ti, length);
p = getLeftAndRight(chars, i, length, '{', '}');
tStartOfElse = (int) p.getKey();
tEndOfElse = (int) p.getValue();
i = tEndOfElse;
} else {
i = tEndOfIf;
}
NumberGet numberGet = new NumberGet();
numberGet.setPro(pro); // 将数据导入
if (Integer.parseInt(numberGet.operation(line.substring(left + 1, right)).toString()) != 0) { // 执行if 语句
readLine(line.substring(tStartOfIf + 1, tEndOfIf));
} else { // 执行else 语句
if (tStartOfElse != -1 && tEndOfElse != -1) {
readLine(line.substring(tStartOfElse + 1, tEndOfElse));
}
}
return i;
}
// 执行while
private int runWhile(String line, int start, int end) throws OperationException {
char[] chars = line.toCharArray();
int length = end;
int i = start;
i = clearSpace(chars, i, length);
// 获取()内的内容
Pair p = getLeftAndRight(chars, i, length, '(', ')');
int left = (int) p.getKey();
int right = (int) p.getValue();
i = clearSpace(chars, right + 1, length);
// 获取{}内的内容
p = getLeftAndRight(chars, i, length, '{', '}');
int startOfWhile = (int) p.getKey();
int endOfWhile = (int) p.getValue();
NumberGet numberGet = new NumberGet();
numberGet.setPro(pro); // 将数据导入
// 执行while循环
while (Integer.parseInt(numberGet.operation(line.substring(left + 1, right)).toString()) != 0) {
readLine(line.substring(startOfWhile + 1, endOfWhile));
}
return endOfWhile;
}
// 执行for
private int runFor(String line, int start, int end) throws OperationException {
char[] chars = line.toCharArray();
int length = end;
int i = start;
i = clearSpace(chars, i, length);
// 获取()内的内容
Pair p = getLeftAndRight(chars, i, length, '(', ')');
int left = (int) p.getKey();
int right = (int) p.getValue();
// 分析()内的内容
String temp = line.substring(left + 1, right);
String firstStr = temp.substring(0, temp.indexOf(';'));
temp = temp.substring(temp.indexOf(';') + 1);
String secondStr = temp.substring(0, temp.indexOf(';'));
String thirdStr = temp.substring(temp.indexOf(';') + 1);
i = clearSpace(chars, right + 1, length);
// 获取{}内的内容
p = getLeftAndRight(chars, i, length, '{', '}');
int startOfFor = (int) p.getKey();
int endOfFor = (int) p.getValue();
NumberGet numberGet = new NumberGet();
numberGet.setPro(pro); // 将数据导入
// 执行for循环
for (readLine(firstStr, 0, firstStr.length()); Integer.parseInt(numberGet.operation(secondStr).toString()) != 0; readLine(thirdStr, 0, thirdStr.length())) {
readLine(line.substring(startOfFor + 1, endOfFor));
}
return endOfFor;
}
// 计算从start到end的识别,主要识别关键字。
public Map<String, Map<String, Object>> getPro() {
return pro;
}
public Object readLine(String line, int start, int end) throws OperationException {
// System.out.println("当前运行语句为:" + line);
char[] chars = line.toCharArray();
int length = end;
int i = start;
Pair p = new Pair(0, "None");
// 去空格
i = clearSpace(chars, i, length);
String leftStr = new String(); // 左边操作对象,有可能是关键字。
// 检测
p = getLeftStr(chars, i, length);
leftStr = (String) p.getValue();
i = (int) p.getKey();
// 判断关键字,进行相应操作
if (keyword.get(leftStr) != null) {
// System.out.println("关键字:" + leftStr);
switch (keyword.get(leftStr)) {
case 1: // if else
i = runIFAndElse(line, i, length);
break;
case 2: // while
i = runWhile(line, i, length);
break;
case 3: // for
i = runFor(line, i, length);
break;
}
} else {
int tEnd = line.indexOf(';', start);
if (tEnd == -1) {
tEnd = end;
}
p = getValue(line, start, tEnd);
i = (int) p.getKey();
// System.out.println("当前结果为:" + line.substring((int) p.getKey()) + "||" + p);
}
if (i + 1 >= length) {
return p.getValue();
} else {
String str = line.substring(i + 1, length);
return readLine(str, 0, str.length());
}
}
public Object readLine(String line) throws OperationException {
return readLine(line, 0, line.length());
}
public Object readLineFromFile(String fileName) throws OperationException, UnsupportedEncodingException, FileNotFoundException, IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8"));
StringBuffer out = new StringBuffer();
String line = null;
while ((line = in.readLine()) != null) {
out.append(line);
}
String str = out.toString();
return readLine(str, 0, str.length());
}
public static void main(String[] args) throws OperationException, FileNotFoundException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
GC gc = new GC();
String fileName = "C:\\Users\\lol\\Desktop\\do.txt";
Class c = Class.forName("util.User");
Object o= c.newInstance();
System.out.println(o);
gc.readLineFromFile(fileName);
System.out.println(gc.getPro());
}
}
第三步: 函数处理
还记得上面的if else for while 嘛?这个其实就是函数,只不过调用的方法有点奇特,其实是一样的,根据上面的代码,我们只需要增加函数定义,并把函数加入到关键字判断即可。
那么有人问了,那函数是可动态加载的还是静态内置的呢?这个问题的话,你可以加一些常用的函数,作为静态内置。
动态加载的,都是利用我们这个解释器语言(还没有起名字- -)写的,那么我们只需要记住他的起始点和结束点即可,其他的只需要调用readLine即可啦。