用C++從0開始開發自己的程式語言
導語
製作程式語言是一項很有趣但也有難度的活,準備徐徐道來,慢慢推進與講解程式語言直譯器的演算法和程式碼。
都說程式設計師的最大理想就是開發出自己的程式語言來,現在,我也開始完成我最大的理想——開發我屬於我自己的程式語言。
閱讀了許多關於自制程式語言的書籍,可略感失望,感覺很多都是使用yacc/lex這些他人寫好的工具生成程式碼,從而製作直譯器,唯一得到的幫助就是直譯器的大概基本原理和結構。
取名記
名字,是一個好專案很重要的一點,我絞盡腦汁思索許久,終於創造出來一個英語短語:BerryMath。為什麼取這個名呢?首先Berry就是漿果,梅的意思,然後Math是數學的意思,翻譯成中文就是數梅語言。因為Berry是我比較喜歡吃的一項水果型別????,並且在程式設計中數學是非常重要的一環,所以取名BerryMath。
使用語言
為了速度和跨平臺性著想,我選擇C++語言進行編寫。
專案連結
專案架構
專案架構圖
專案檔案結構
- include
- BerryMath.h
- interpreter.h
- value.h
- ast.h
- lex.h
- include
- BerryMath.cpp
- interpreter.cpp
- value.cpp
- ast.cpp
- lex.cpp
- main.cpp
直譯器流程
著手實現
介面檔案編寫
首先建立BerryMath.h和BerryMath.cpp檔案,後期擴充開發等都需要引入該標頭檔案
include/BerryMath.h
#ifndef BERRYMATH_BERRYMATH_H
#define BERRYMATH_BERRYMATH_H
#include "value.h"
#include "lex.h"
namespace BM {
}
#endif //BERRYMATH_BERRYMATH_H
src/BerryMath.cpp
#include "BerryMath.h"
語言記憶體實現
首先,這門語言我設計是動態型別語言,萬物皆物件,所以記憶體部分設計如下:
並且,為了記憶體管理,編寫妥善的垃圾回收機制,我們在基類Object中需要用unsigned long型別的linked屬性以儲存引用次數。這樣在執行解構函式時,遍歷所以屬性,linked減一,爾後linked為0的就是沒有任何Object或者後面的Variable類應用,即可刪除了。
接著,為了便於除錯檢視,和後面編寫語言擴充庫時print等函式的編寫,基類Object應當還有toString()成員函式用於返回std::string型別的值, 並有private的print函式用於列印資料,最後過載運算子,使得其可以被ostream類的例項化物件輸出,比如cout。
在這時,我們還要考慮一點:toString轉換有一個小bug:如果object的屬性中有一個屬性或屬性的屬性的值是自己(即迴圈呼叫),就會陷入死迴圈,所以我們還需要一個parent物件儲存父節點,並有一個has成員函式用於判斷某值是否是祖先節點,如果是,就將那個值toString的值為…。
然後呢,我們開始看一些有關屬性讀寫的成員函式。
首先,我們需要一個插入值的函式,insert,需要接受std::string和Object*,這個函式流程主要是:插入屬性值,增加引用計數,將值的parent屬性設為自己。
有set函式,用於寫屬性值,如果沒有該屬性,就insert進去,有就修改,流程基本同insert
有get函式,用於獲得某屬性的值,return Object*型別的值。
還有del函式,用於刪除某屬性,首先找到該屬性的值,然後從proto中刪除,引用計數減一,如果引用計數為0,delete.
最後,解構函式,也與del函式類似,不過是遍歷每一個屬性,刪除每一個屬性罷了。
最後include/value.h、src/value.cpp程式碼如下:
include/value.h
#ifndef BERRYMATH_VALUE_H
#define BERRYMATH_VALUE_H
#include <iostream>
#include <string>
#include <map>
#include <sstream>
using std::string;
using std::map;
typedef unsigned long UL;
namespace BM {
class Object {
public:
Object() : linked(0), parent(nullptr) { }
bool has(Object*, Object*);
void set(const string &key, Object *value);
void insert(string, Object*);
Object* get(const string &key);
void del(const string &key);
Object& operator[](const string &key) { return *get(key); }
UL links() { return linked; }
UL bind() { return ++linked; }
UL unbind() { return --linked; }
virtual string toString(bool = true, bool = true, string = "");
virtual Object* copy() {
auto object = new Object();
for (auto iter = proto.begin(); iter != proto.end(); iter++) {
object->set(iter->first, iter->second->copy());
}
return object;
}
virtual ~Object();
friend std::ostream& operator<<(std::ostream& o, Object& v) {
v.print(o);
return o;
}
protected:
void print(std::ostream&, bool = true);
UL linked;
map<string, Object*> proto;
Object* parent;
};
class Number : public Object {
public:
Number() : Object(), v(0) { }
Number(double t) : Object(), v(t) { }
string toString(bool = true, bool hl = true, string tab = "") {
string o("");
std::ostringstream oss;
oss << v;
if (hl) o += "
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2310/viewspace-2823084/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 從 0 開始實現程式語言(一):手寫 jsonParserJSON
- C語言從零開始(一)C語言
- 從0開始搭建preact開發環境React開發環境
- JavaWeb專案開發從0開始的要點!JavaWeb
- C++程式設計從零開始之語句(轉)C++程式設計
- 從零開始學C語言pdfC語言
- 從零開始——GO語言基礎語法Go
- 授予漁,從0開始搭建一個自己想要的網頁網頁
- 易語言陣列 ,索引從 1 開始。陣列索引
- 從 0 開始構建一個屬於你自己的 PHP 框架PHP框架
- 從0開始構建一個屬於你自己的PHP框架PHP框架
- 國人開發的程式語言-“明”語言
- Python語言的創始人解釋為什麼Python陣列的索引從0開始Python陣列索引
- Python 語言的創始人解釋為什麼 Python 陣列的索引從0開始Python陣列索引
- 從零開始的PHP開發逆天路——語法PHP
- 開發自己的前端工具庫(二):函數語言程式設計前端函數程式設計
- 從 0 開始瞭解 DockerDocker
- 從 0 開始學架構架構
- 從0開始,手把手教你用Vue開發一個答題AppVueAPP
- 為什麼程式要從0開始計數
- 從0開始開發網頁,需要學什麼?(小白向)網頁
- [敏捷開發實踐](0) 開始敏捷
- 從零開始學C語言 第3版pdfC語言
- 搞安全開發都是用什麼程式語言?
- 從零開始:開發一款應用程式的完整流程技巧
- 從0開始學習java,應該從那塊開始學起?Java
- 從0開始的高併發(一)--- Zookeeper的基礎概念
- 微信小程式開發教程-從零開始(1)微信小程式
- 微信小程式開發教程-從零開始(2)微信小程式
- 微信小程式開發教程-從零開始(3)微信小程式
- VuePress從零開始搭建自己的部落格Vue
- 從0開始學習Webpack(一)Web
- 從0開始fastjson漏洞分析ASTJSON
- uni-app 小程式從零開始的開發流程APP
- 從零開始學Python(一):Python語言的背景,發展,以及前景.Python
- 從0開始學遊戲開發-蔡能-極客時間遊戲開發
- 【機器學習】從0開始的啃西瓜指導機器學習
- 各行業都愛用什麼程式語言開發?行業