C++で0から独自のプログラミング言語を開発
50613 ワード
目次ガイド 名前記 使用言語 プロジェクトリンク プロジェクトアーキテクチャ プロジェクトアーキテクチャ図 プロジェクトファイル構造 インタプリタフロー の実装に着手インタフェースファイル作成 言語メモリ を実現
ガイド人
これは私が初めて文章を出す準備をして、ゆっくりとプログラミング言語解釈器のアルゴリズムとコードを推進して説明する準備をします.プログラマーの最大の理想は自分のプログラミング言語を開発することだと言われています.今、私も私の最大の理想を完成し始めました.私は自分のプログラミング言語を開発します.自作プログラミング言語に関する多くの本を読んだが、少しがっかりした.yacc/lexなどの他人が書いたツールを使ってコードを生成し、解釈器を作ることが多いような気がした.唯一の助けは解釈器の基本原理と構造だ.
名づけ記
名前、1つの良いプロジェクトのとても重要な点で、私は長い間頭を絞って考えて、ついに1つの英語のフレーズを創造しました:BerryMath.どうしてこの名前をつけたのですか.まずBerryはベリー、梅の意味で、それからMathは数学の意味で、中国語に訳すと数梅言語です.Berryは私の好きな果物のタイプだから?そしてプログラミングにおいて数学は非常に重要な一環であるため,BerryMathと名付けられた.
言語の使用
スピードとクロスプラットフォーム性のために、C++言語を選んで書きました.
プロジェクトリンク
https://github.com/BerryMathDevelopmentTeam/BerryMath
プロジェクトアーキテクチャ
プロジェクトアーキテクチャ図
ワードアナライザ
抽象構文ツリービルダー
言語インタプリタ
言語メモリ構造
プロジェクトファイル構造 include BerryMath.h interpreter.h value.h ast.h lex.h
include BerryMath.cpp interpreter.cpp value.cpp ast.cpp lex.cpp
main.cpp
インタプリタフロー
Created with Raphaël 2.2.0新規インタプリタ構文解析を開始抽象構文ツリー解析を構築抽象構文ツリーBerryMathスクリプトを実行して終了しますか?回収メモリ終了yes no
実現に着手する.
インタフェースファイルの作成
まずBerryMathを作成します.時間とBerryMath.cppファイル、後期開拓開発などは、このヘッダファイルinclude/BerryMathを導入する必要がある.h
src/BerryMath.cpp
言語メモリの実装
まず、この言語はダイナミックタイプの言語で、万物が対象なので、メモリの部分は以下のように設計されています.
Object Number String Null Undefind派生派生proto属性はhash mapであり、keyとvalue(std::map<:string bm::object="""">)を格納するdoubl eタイプを持つ.格納数にstdを持つ.stri ngタイプは文字列Object Number String Null Undefindを格納する.
また,メモリ管理のために適切なゴミ回収メカニズムを記述するためには,ベースクラスObjectにunsigned longタイプのlinked属性を用いて参照回数を格納する必要がある.これにより、構造解析関数を実行するときに属性を巡回し、linkedを1つ減らし、その後linkedを0にしたのは、Objectや後のVariableクラスアプリケーションがなく、削除できます.次に、デバッグ表示を容易にし、言語拡張ライブラリを後で作成する際のprintなどの関数の作成を容易にするために、ベースクラスObjectにはstd::stringタイプの値を返すためのtoString()メンバー関数があり、privateのprint関数がデータの印刷に使用され、最後に演算子が再ロードされ、coutなどのostreamクラスのインスタンス化オブジェクトによって出力されるようにしなければならない.この場合、toString変換には小さなバグがあります.objectの属性に属性または属性の値が自分(すなわちループ呼び出し)である場合、デッドループに陥るため、parentオブジェクトが親ノードを格納し、ある値が祖先ノードであるかどうかを判断するhasメンバー関数が必要です.その値toStringの値を....次に、プロパティの読み書きに関するメンバー関数を見てみましょう.まず、値を挿入する関数、insert、std::stringとObject*を受け入れる必要があります.この関数の流れは主に、属性値を挿入し、参照カウントを増やし、値のparent属性を自分に設定することです.set関数があって、属性の値を書くために用いて、もしこの属性がないならば、insertは入って、あったら修正して、流れは基本的にinsertとget関数があって、ある属性の値を得るために用いて、return Object*タイプの値.また、del関数は、ある属性を削除するために使用され、まずその属性の値を見つけ、protoから削除し、参照カウントを1つ減らし、参照カウントが0の場合、delete.最後に,構造関数もdel関数と類似しているが,各属性を遍歴し,各属性を削除するにすぎない.最後にh、src/value.cppコードは以下の通りである:include/value.h
src/value.cpp
以上、メモリ管理部はほぼ完了しています.
[未完待機]
ガイド人
これは私が初めて文章を出す準備をして、ゆっくりとプログラミング言語解釈器のアルゴリズムとコードを推進して説明する準備をします.プログラマーの最大の理想は自分のプログラミング言語を開発することだと言われています.今、私も私の最大の理想を完成し始めました.私は自分のプログラミング言語を開発します.自作プログラミング言語に関する多くの本を読んだが、少しがっかりした.yacc/lexなどの他人が書いたツールを使ってコードを生成し、解釈器を作ることが多いような気がした.唯一の助けは解釈器の基本原理と構造だ.
名づけ記
名前、1つの良いプロジェクトのとても重要な点で、私は長い間頭を絞って考えて、ついに1つの英語のフレーズを創造しました:BerryMath.どうしてこの名前をつけたのですか.まずBerryはベリー、梅の意味で、それからMathは数学の意味で、中国語に訳すと数梅言語です.Berryは私の好きな果物のタイプだから?そしてプログラミングにおいて数学は非常に重要な一環であるため,BerryMathと名付けられた.
言語の使用
スピードとクロスプラットフォーム性のために、C++言語を選んで書きました.
プロジェクトリンク
https://github.com/BerryMathDevelopmentTeam/BerryMath
プロジェクトアーキテクチャ
プロジェクトアーキテクチャ図
ワードアナライザ
抽象構文ツリービルダー
言語インタプリタ
言語メモリ構造
プロジェクトファイル構造
インタプリタフロー
Created with Raphaël 2.2.0新規インタプリタ構文解析を開始抽象構文ツリー解析を構築抽象構文ツリーBerryMathスクリプトを実行して終了しますか?回収メモリ終了yes no
実現に着手する.
インタフェースファイルの作成
まずBerryMathを作成します.時間と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 Number String Null Undefind派生派生proto属性はhash mapであり、keyとvalue(std::map<:string bm::object="""">)を格納するdoubl eタイプを持つ.格納数にstdを持つ.stri ngタイプは文字列Object Number String Null Undefindを格納する.
また,メモリ管理のために適切なゴミ回収メカニズムを記述するためには,ベースクラスObjectにunsigned longタイプのlinked属性を用いて参照回数を格納する必要がある.これにより、構造解析関数を実行するときに属性を巡回し、linkedを1つ減らし、その後linkedを0にしたのは、Objectや後のVariableクラスアプリケーションがなく、削除できます.次に、デバッグ表示を容易にし、言語拡張ライブラリを後で作成する際のprintなどの関数の作成を容易にするために、ベースクラスObjectにはstd::stringタイプの値を返すためのtoString()メンバー関数があり、privateのprint関数がデータの印刷に使用され、最後に演算子が再ロードされ、coutなどのostreamクラスのインスタンス化オブジェクトによって出力されるようにしなければならない.この場合、toString変換には小さなバグがあります.objectの属性に属性または属性の値が自分(すなわちループ呼び出し)である場合、デッドループに陥るため、parentオブジェクトが親ノードを格納し、ある値が祖先ノードであるかどうかを判断するhasメンバー関数が必要です.その値toStringの値を....次に、プロパティの読み書きに関するメンバー関数を見てみましょう.まず、値を挿入する関数、insert、std::stringとObject*を受け入れる必要があります.この関数の流れは主に、属性値を挿入し、参照カウントを増やし、値のparent属性を自分に設定することです.set関数があって、属性の値を書くために用いて、もしこの属性がないならば、insertは入って、あったら修正して、流れは基本的にinsertとget関数があって、ある属性の値を得るために用いて、return Object*タイプの値.また、del関数は、ある属性を削除するために使用され、まずその属性の値を見つけ、protoから削除し、参照カウントを1つ減らし、参照カウントが0の場合、delete.最後に,構造関数もdel関数と類似しているが,各属性を遍歴し,各属性を削除するにすぎない.最後にh、src/value.cppコードは以下の通りである:include/value.h
#ifndef BERRYMATH_VALUE_H
#define BERRYMATH_VALUE_H
#include
#include
#include
#include
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 += "\033[33m";
o += oss.str();
if (hl) o += "\033[0m";
return o;
}
double& value() { return v; }
Object* copy() {
return new Number(v);
}
~Number() { }
private:
double v;
};
class String : public Object {
public:
String() : Object(), v("") { }
String(const string& t) : Object(), v(t) { }
string toString(bool = true, bool hl = true, string tab = "") {
string o("");
if (hl) o += "\033[32m";
o += "\"" + v + "\"";
if (hl) o += "\033[0m";
return o;
}
string& value() { return v; }
Object* copy() {
return new String(v);
}
~String() { }
private:
string v;
};
class Null : public Object {
public:
Null() : Object() { }
string toString(bool = true, bool hl = true, string tab = "") {
string o("");
if (hl) o += "\033[36m";
o += "null";
if (hl) o += "\033[0m";
return o;
}
Object* copy() {
return new Null;
}
~Null() { }
};
class Undefined : public Object {
public:
Undefined() : Object() { }
string toString(bool = true, bool hl = true, string tab = "") {
string o("");
if (hl) o += "\033[35m";
o += "undefined";
if (hl) o += "\033[0m";
return o;
}
Object* copy() {
return new Undefined;
}
~Undefined() { }
};
}
#endif //BERRYMATH_VALUE_H
src/value.cpp
#include "../include/value.h"
bool BM::Object::has(Object *v, Object* root = nullptr) {
if (!root) root = this;
if (this == v || parent == v) return true;
if (parent == root) return false;
if (parent && parent != this) return parent->has(v, root);
return false;
}
string BM::Object::toString(bool indent, bool hl, string tab) {
string o("{");
if (indent) {
o += "
";
tab += "\t";
}
auto iter = proto.begin();
auto end = proto.end();
for (; iter != end; iter++) {
const string& key = iter->first;
if (key[0] == '_' && key[1] == '_') continue;//
o += tab;
if (hl) {
o += "\033[32m\"" + key + "\"\033[0m";
} else {
o += "\"" + key + "\"";
}
o += ": ";
if (has(iter->second)) o += "...";
else o += iter->second->toString(indent, hl, tab);
o += ",";
if (indent) o += '
';
}
if (indent) {
tab.pop_back();
o += tab;
}
o += "}";
return o;
}
void BM::Object::print(std::ostream &o, bool hl) {
o << toString(true, hl) << std::endl;
}
void BM::Object::set(const string &key, Object *value) {
if (proto.count(key) == 0) {
insert(key, value);
} else {
proto[key] = value;
if (this != value) value->linked++;
value->parent = this;
}
}
BM::Object* BM::Object::get(const string &key) {
auto iter = proto.find(key);
if (iter == proto.end()) return nullptr;
return iter->second;
}
void BM::Object::insert(string key, Object *value) {
proto.insert(std::pair<string, Object*>(key, value));
if (this != value) value->linked++;
value->parent = this;
}
void BM::Object::del(const string &key) {
auto iter = proto.find(key);
if (iter == proto.end()) return;,
proto.erase(iter);
Object* v = iter->second;
v->linked--;
if (v->linked < 1) delete v;
}
BM::Object::~Object() {
for (auto iter = proto.begin(); iter != proto.end(); iter++) {
Object* v = iter->second;
if (!v || v->linked < 1 || has(v)) continue;
v->linked--;
if (v->linked < 1) delete v;
iter->second = nullptr;
}
proto.clear();
}
以上、メモリ管理部はほぼ完了しています.
[未完待機]