用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
- 從0開始搭建自己的直播平臺
- 從0開始用MavenMaven
- 從零開始學習C++(0)C++
- 從0開始搭建preact開發環境React開發環境
- JavaWeb專案開發從0開始的要點!JavaWeb
- 從零開始學C語言pdfC語言
- 從零開始——GO語言基礎語法Go
- 授予漁,從0開始搭建一個自己想要的網頁網頁
- 【筆記】從0開始的程式碼審計筆記
- 202409071506,開始寫程式碼,從0開始 驗證基本架子
- 易語言陣列 ,索引從 1 開始。陣列索引
- 開發自己的前端工具庫(二):函數語言程式設計前端函數程式設計
- 為什麼程式要從0開始計數
- 從 0 開始學架構架構
- 從0開始fastjson漏洞分析ASTJSON
- 從 0 開始瞭解 DockerDocker
- 從零開始的PHP開發逆天路——語法PHP
- 從0開始,手把手教你用Vue開發一個答題AppVueAPP
- 搞安全開發都是用什麼程式語言?
- 從0開始開發網頁,需要學什麼?(小白向)網頁
- 從零開始學C語言 第3版pdfC語言
- 從零開始學習C++之if判斷語句C++
- 從零開始:開發一款應用程式的完整流程技巧
- 從0開始的高併發(一)--- Zookeeper的基礎概念
- 從0開始建立自己的部落格:前言
- 從0開始fastjson漏洞分析2ASTJSON
- 從0開始學習Webpack(一)Web
- 從0開始設計Flutter獨立APP | 第二篇: 完整的國際化語言支援FlutterAPP
- 從0到1開發一款自己的vscode外掛VSCode
- VuePress從零開始搭建自己的部落格Vue
- uni-app 小程式從零開始的開發流程APP
- 從0開始學遊戲開發-蔡能-極客時間遊戲開發
- 各行業都愛用什麼程式語言開發?行業
- VsCode從零開始配置一個屬於自己的Vue開發環境VSCodeVue開發環境
- 從零開始學Python:19課-使用PyCharm開發Python應用程式PythonPyCharm
- 《黑神話·悟空》是用什麼程式語言開發的?
- Slack是用Hack語言開發