上一節我們從模型上重建了AST節點,將antlr生成的表達式AST抽象成可直接運算的AST節點。
在運算之前我們必須首先定義出數據類型,定義出腳本支持的數據類型,這是運算的基礎。
這一小節我們將定義出數據類型,在這里我們暫時定義四個數據類型:
enum Type { String, Number, Bool, Object, None };
完整的數據類型定義如下:
/// .h
typedef double number;
namespace DynamicDSL {
enum Type { String, Number, Bool, Object, None };
struct SemaASTNodeObject {
private:
any value;
public:
SemaASTNodeObject() {}
SemaASTNodeObject(any value) {
this->value = value;
}
~SemaASTNodeObject() { }
public:
const Type getType();
const string getTypeText();
const any getRawValue() { return this->value; }
void setValue(any v) { this->value = v; }
/// 獲取數據的字符串描述
const string getText();
template
這里我們使用了any來包裝我們具體的數據,所以我們的C++編譯器需要設置成C++ 17
String類型我們使用的是std::string來實現。
Number類型則是上面提到的使用double來實現的。
Bool類型則是使用bool實現。
Object類型是單獨定義的一個C++類型或者本身就是一個SemaASTNodeObject,后面單獨說明。
通過std::any中的type()函數獲取放置的數據信息來判斷放置的數據的類型:
const DynamicDSL::Type DynamicDSL::SemaASTNodeObject::getType() {
string clsName = this->value.type().name();
if(clsName == "i" || clsName == "d") return Number;
else if(clsName.find("string") != string::npos) return String;
else if(clsName == "b") return Bool;
else if(clsName.find("SemaASTNodeObject") != string::npos ||
clsName.find("SemaContext") != string::npos)
return Object;
else if(clsName == "v") return None;
else {
return None;
}
}
解包的時候判斷再轉換成具體的數據類即可,它的實現如下:
const string DynamicDSL::SemaASTNodeObject::getText() {
if(this->value.has_value()) {
if(getType() == String) {
return any_cast<string>(this->value);
} else if(getType() == Number) {
ostringstream oss;
oss << any_cast<double>(this->value);
return oss.str();
} else if(getType() == Bool) {
if(any_cast<bool>(this->value)) return "true";
else return "false";
} else if(getType() == Object) {
string clsName = this->value.type().name();
if(clsName.find("SemaASTNodeObject") != string::npos) {
return getValue
為里需要特別說明一下Object這個類型中的另外一個自定義數據類型SemaContext。
它的完整定義如下:
namespace DynamicDSL {
enum JSONType {
JSONType_String,
JSONType_Number,
JSONType_Bool,
JSONType_Object,
JSONType_None
};
}
namespace DynamicDSL {
class SemaContext {
private:
/// 本地變量
map<string, SemaASTNodeObject> variable;
/// JSON注入
Json json;
public:
SemaContext(Json json) {
this->json = json;
}
SemaContext(Json json, map<string, SemaASTNodeObject> variable) {
this->json = json;
this->variable = variable;
}
static SemaContext *copy(SemaContext *context) {
return new SemaContext(context->getJSON(), context->getVariable());
}
public:
map<string, SemaASTNodeObject> getVariable() { return variable; }
Json getJSON() { return json; }
void putVariable(string key, SemaASTNodeObject val) {
variable[key] = val;
}
SemaASTNodeObject getVariableValue(string key) {
if(variable.count(key) > 0) return variable[key];
DynamicDSL::SemaASTNodeObject object;
if(!json[key].is_null()) {
Json jsonValue = json[key];
JSONType type = SemaContext::getValueType(jsonValue);
if(type == DynamicDSL::JSONType_Bool) {
object.setValue(jsonValue.bool_value());
} else if(type == DynamicDSL::JSONType_Number) {
object.setValue(jsonValue.number_value());
} else if(type == DynamicDSL::JSONType_String) {
object.setValue(jsonValue.string_value());
} else if(type == DynamicDSL::JSONType_Object) {
auto context = SemaContext(jsonValue);
object.setValue(context);
}
}
return object;
}
static JSONType getValueType(Json jsonObject) {
if(jsonObject.is_string()) return DynamicDSL::JSONType_String;
else if(jsonObject.is_number()) return DynamicDSL::JSONType_Number;
else if(jsonObject.is_bool()) return DynamicDSL::JSONType_Bool;
else if(jsonObject.is_object()) return DynamicDSL::JSONType_Object;
return DynamicDSL::JSONType_None;
}
};
};
這個類定義了棧幀執行時的變量上下文環境,由于特殊的使用場景,還多定義了一個注入的Json對象,這個Json對象在使用模板一開始的時候就注入了。
棧運行過程中產生的臨時變量放入variable容器中,目前執行環境都是單獨的一個表達式樹,在沒有對象與函數實現之前,這個執行環境比較單純,這里只是提前考慮到執行環境這個問題,后期加入類與函數實現的時候可以更方便改造。
后面我們在消解變量的時候就需要從當前這個環境中查找對應的數據,找到后打包成一個SemaASTNodeObject對象,他的具體執行邏輯是這樣的:
SemaASTNodeObject getVariableValue(string key) {
if(variable.count(key) > 0) return variable[key];
DynamicDSL::SemaASTNodeObject object;
if(!json[key].is_null()) {
Json jsonValue = json[key];
JSONType type = SemaContext::getValueType(jsonValue);
if(type == DynamicDSL::JSONType_Bool) {
object.setValue(jsonValue.bool_value());
} else if(type == DynamicDSL::JSONType_Number) {
object.setValue(jsonValue.number_value());
} else if(type == DynamicDSL::JSONType_String) {
object.setValue(jsonValue.string_value());
} else if(type == DynamicDSL::JSONType_Object) {
auto context = SemaContext(jsonValue);
object.setValue(context);
}
}
return object;
}
首先從臨時變量中查找,如果找到了就直接返回,如果沒找到就從注入的Json對象就查找。
到此,我們的類型系統就實現完成了, 我們還實現了棧幀執行的環境上下文。
下一節我們將在此基礎上實現簡最單純的棧幀
-
運算
+關注
關注
0文章
127瀏覽量
25687 -
數據類型
+關注
關注
0文章
229瀏覽量
13535 -
定義
+關注
關注
0文章
10瀏覽量
14268
發布評論請先 登錄
相關推薦
![](https://file1.elecfans.com/web2/M00/88/22/wKgaomRmo22ASV3fAACdYLG5sjk831.png)
![](https://file1.elecfans.com/web2/M00/88/22/wKgaomRmo3uAOhwWAACHJgz_WkA348.png)
單片機中宏定義與重新定義數據類型(typedef)區別
求助,插補判別F 怎樣定義數據類型?
LabVIEW自定義數據類型
請問如何自定義128位數據類型
嵌入式ARM開發之自定義數據類型相關資料推薦
C++程序設計教程之自定義數據類型的詳細資料說明
![C++程序設計教程之自<b class='flag-5'>定義</b><b class='flag-5'>數據類型</b>的詳細資料說明](https://file.elecfans.com/web1/M00/89/9F/pIYBAFyKDoWAYnPhAATiMCIbnsc734.png)
SystemVerilog為工程師定義新的數據類型提供了一種機制
用戶定義數據類型的結構
博途PLC1200/1500PLC用戶自定義數據類型(UDT)
![博途PLC1200/1500PLC用戶自<b class='flag-5'>定義</b><b class='flag-5'>數據類型</b>(UDT)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
西門子PLC UDT數據類型的使用方法
![西門子PLC UDT<b class='flag-5'>數據類型</b>的使用方法](https://file1.elecfans.com/web2/M00/8D/2B/wKgZomS3itGAHBUCAAAvgGb2gew526.png)
評論