起初最早聽到lisp這個名字是一個偶然的機會,留下了很牛的印象,時間匆匆五年就過去了,前些日子看sicp,裡面又再次提到了這個名字,從網上找了幾個入門文件學習了一下基礎語法,便又繼續看起了sicp;從寫下第一行(+ 1 2)程式碼,日子轉眼一個月就過去了,不得不說 lisp的字首表示式的方式還是很不錯的,不知怎得慢慢有了寫一個lisp 直譯器的想法,然後想到了之前王垠似乎寫過一篇文章《怎樣寫一個直譯器》 如果你對如何寫一個直譯器感興趣可以看下這篇文章,還是有所啟發的。
回來了嗎?哈哈哈
我們繼續旅途
寫一個lisp直譯器可以分三步:
1.將lisp表示式的字串轉換成一個樹性結構的陣列
2.解釋這棵樹
3.支援變數和方法呼叫
這裡使用的語言是java
構造語法樹
首先第一步:如何將lisp表示式的字串轉換成一個樹性結構的陣列?
我們看一幾個lisp表示式 分析一下他的構成
(+ 1 2)
(+ 1 2 (- 3 4))
(+ 1 2 (- 3 4) 5)
(+ 1 2 (- 3 4) 5 (+ 6 7 (+ 8 9)))
(+ 1 2 (- 3 4) (+ 5 6 (+ 7 8)))
(+ 1 2 (- 3 4) (+ 5 6 (+ 7 8)) 9)
可以看到以上表示式裡面可以分成兩種元素:一個是不可分割的最小元素如 + - 1 2 3 這種 ,還有 (- 3 4)這種複合元素,而複合元素也是由最小的基礎元素構成,於是我們得到了第一個規則(複合元素可以被拆分成更小的基礎元素和複合元素)。
以(+ 1 2 (- 3 4) 5 (+ 6 7 (+ 8 9)))這個表示式為例,它如果是一棵樹長什麼樣子呢?下面讓我們畫出它的形態:
我們有了它的樣子,但要如何將一個字串形式的表示式轉換成這樣一棵樹呢? 這是我們接下來要分析的問題
duang duang duang duang...
讓我們回到我們的第一個規則 這裡還有什麼隱藏資訊呢?
1.複合元素可拆分
2.基礎元素不可拆分
3.複合元素是被“()”包裹的元素
有了這三項我們就可以在進一步的思考了,樹樹樹,樹的元素是什麼?
1.節點
2.葉子節點
眉目,眉目,有了眉目
節點對應的是複合元素,基礎元素對應的是葉子節點,那如何區分複合元素和基礎元素呢?
“3.複合元素是被“()”包裹的元素”,是它,是它,就是它。
複合節點裡的第一個元素是“(”後的第一個元素,最後一個元素是“)”前的第一個元素,我們又得到了第二個規則,有了上面兩個規則我們開始構建我們的第一棵樹:
程式碼:
node
class ExpNode implements Iterable<Object>{
List<Object> data = new ArrayList<>();
Node parent;
public static ExpNode newInstance() {
return new ExpNode();
}
public void add(Object o) {
if (o instanceof ExpNode) {
((ExpNode) o).parent = this;
}
super.add(o);
}
public Iterator<Object> iterator() {
return data.iterator();
}
}
parse
public class Parse {
public static ExpNode parseTree(String exp) {
ExpNode root = ExpNode.newInstance();
buildNode(trimStr(exp), 0, root);
return (ExpNode) root.iterator().next();
}
private static void buildNode(String exp, int level, Cons node) {
int lIndex = exp.indexOf("(");
int rIndex = exp.indexOf(")");
if (rIndex > -1) {
if (lIndex < rIndex && lIndex > -1) {
String subExp = exp.substring(lIndex, rIndex + 1);
if (isBaseLeaf(exp)) {
ExpNode a = parseNode(subExp).orElseThrow(RuntimeException::new);
node.add(a);
} else {
Optional<ExpNode> nodeOptional = parseNode(subExp);
if (nodeOptional.isPresent()) {
ExpNode val = nodeOptional.get();
node.add(val);
node = val;
} else {
ExpNode objects = ExpNode.newInstance();
node.add(objects);
node = objects;
}
}
++level;
log.debug("{}{}---{}", createRepeatedStr(level), exp.substring(lIndex), subExp);
buildNode(exp.substring(lIndex + 1), level, node);
} else {
//) b a (+ 8 9) => ) b a ( => b a
if (lIndex > -1) {
String subExp = trimStr(exp.substring(rIndex + 1, lIndex));
if (subExp.length() > 0 && !subExp.contains(")")) {
String[] values = subExp.split(" ");
for (String val : values) {
node.parent().add(parseObj(val));
}
}
} else {
// 所有都是後退
// ) b a) => b a) => b a
String subExp = exp.substring(rIndex + 1);
int r2Index = 1 + subExp.indexOf(")");
if (r2Index > 1) {
subExp = trimStr(subExp.substring(1, r2Index - 1));
if (subExp.length() > 0) {
String[] values = subExp.split(" ");
for (String val : values) {
node.parent().add(parseObj(val));
}
}
}
}
--level;
log.debug("{}{}", createRepeatedStr(level), exp.substring(rIndex));
buildNode(exp.substring(rIndex + 1), level, node.parent());
}
} else {
log.debug(createRepeatedStr(level));
}
}
private static Optional<ExpNode> parseNode(String exp) {
String subExp = "";
if (isBaseLeaf(exp)) {
//(xx [xx])
subExp = exp.substring(1, exp.length() - 1);
} else {
// (xx [xx] (xx xx xx)
// (xx [xx] (
// ((
subExp = exp.substring(1);
subExp = subExp.substring(0, subExp.indexOf("("));
if (subExp.trim().isEmpty()) {
return Optional.empty();
}
}
String[] keys = subExp.split(" ");
ExpNode node = ExpNode.newInstance();
for (int i = 0; i < keys.length; i++) {
node.add(parseObj(keys[i]));
}
return Optional.of(node);
}
private static Object parseObj(String val) {
try {
return Integer.valueOf(val);
} catch (NumberFormatException e) {
if (val.equals("true") || val.equals("false")) {
return Boolean.valueOf(val);
} else if (val.indexOf("'") == 0 && val.lastIndexOf("'") == val.length() - 1) {
return val.replaceAll("\"", "\"");
} else {
return Var.of(val);
}
}
}
private static boolean isBaseLeaf(String exp) {
return count(exp, "\\(") == 1 && count(exp, "\\)") == 1 && exp.matches("^\\(.+?\\)$");
}
private static int count(String str, String regx) {
Matcher matcher = Pattern.compile(regx).matcher(str);
int i = 0;
while (matcher.find()) {
i++;
}
return i;
}
private static String trimStr(String str) {
String tempStr = str.replace(" ", " ").trim();
return tempStr.contains(" ") ? trimStr(tempStr) : tempStr;
}
private static String createRepeatedStr(int n) {
return String.join("", Collections.nCopies(n, "--"));
}
}
當然還有更簡單的方式 哈哈哈,將“(”替換成“[”,將“)”轉換成“]”,讓後用json 解析器解析即可,哈哈哈哈