前言
這就是一次大型的改動!因爲解釋器的解釋接口是不唯一的,所以在解釋時語法樹的不同節點調用的解釋接口都可能有好幾種情況!!!雖然很亂,但是正是不同的解釋接口才成就了這麼語言的動態類型——變量的類型與根節點調用的解釋接口有關。
仍然處於解釋單條語句的情況,等完成了判斷式的語法樹構造、邏輯式的語法樹構造,就考慮點別的吧!比如if-else和三種循環。。。。
Suatin語言運算優先級
儘管沒有左優先級的枚舉,也沒有獲取優先級的方法,但是這門自制語言裏本質上是存在優先級的,正是根據這優先級才分類不同的情況,來做語法樹!!!
- = 出現左邊的標識符時,語句還是簡單的表達式,當出現等於號後,語句類型就變成了賦值式。簡單表達式的根節點掛在exprRoot上,賦值式的根節點掛在root上!!!
- "this is a string" 當簡單表達式的第一個Token是字符串時,簡單表達式變成字符串拼接模式,第一個字符串後面加上的內容也應該是字符串。最後exprRoot掛載的根節點也返回一個拼接好的字符串。
- and,or,not 出現這個後,表達式變爲邏輯模式,【下篇再講】
- >,<,>=,<=,==,~= 在沒有邏輯運算的情況下,一個式子只能有一個判斷運算符,判斷運算符兩邊各有一個簡單表達式(不能是字符串)。存在判斷運算符時,表達式變成判斷模式,判斷模式的表達式的根節點掛在judgeRoot上。
- () 每次出現一個左括號就創建一個左括號節點,在沒有匹配到右括號之前,出現的符號都在這個左括號節點下面處理。
- ^ 左結合與右結合。當簡單表達式只有一個數(或者語法樹的【根節點】是個左括號節點)時,將該數(或該小樹)放到乘方節點左孩子上。否則,找到最右的樹枝節點,把該樹枝節點的右孩子取下,作爲新乘方節點的左孩子,把新乘方樹裝上該樹枝節點的右孩子上!!!
- */ 左結合與右結合。當簡單表達式的【根節點】不是加減時,把其放到乘除的左孩子上。否則,找到【根節點】的右孩子,取下該右孩子作爲乘除節點的左孩子,再把新乘除樹裝上【根節點】的有孩子上。
- +- 左結合。每次出現加減都要把之前的語法樹【根節點】放到加減節點的左孩子上。
- 注:【根節點】不一定是根節點,可能是左括號節點下的小語法樹的根節點!!!
interpret接口
interpret接口與interpret_str接口之前我都寫成了純虛函數,**但是!!**因爲子類返回的數據類型不同,所以有的子類不會使用到兩個接口,但是因爲接口是純虛的,所以雖然只用一個接口,但是我還是要寫另一個接口的空的實現!!!
結果就是增加一個接口,修改所有的類!
所以要寫成虛函數!!!子類只實現自己需要的接口就行了!!!
增加了interpret_bool接口後
#語句##語法樹##各個節點調用的解釋接口#如下所示
a = 1 + 1 > 3;
= -> interpret_bool
/ \ / \
a > interpret_bool
/ \ / \
+ 3 interpret interpret
/ \ / \
1 1 interpret interpret
解釋器現在的類
目前項目總共有20個類。
變量特殊賦值
之前寫的EqExpr賦值節點的解釋方法裏,我傳遞的是等於號右邊的語法樹返回的值(或者字符串),但是一個變量除了值之外,比如類型等數據。
判斷運算
之前引入了左括號節點、賦值節點,這次引入了>,<,>=,<=,==,~=6個節點類,操作都類似。
//大於號解析器 >
class GreExpr : public SymbolExpr {
public:
GreExpr(Expr* _left, Expr* _right) : SymbolExpr(_left, _right) {}
~GreExpr() {}
virtual GreExpr* GetClassType() { return this; }
virtual bool interpret_bool(){
return left->interpret() >= right->interpret();
}
};
引入判斷運算
對於簡單表達式來說,只操作下面幾個指針或容器。
//普通表達式要構造語法樹用得到的指針
Expr* exprRoot = NULL; //表達式語法樹根節點
Expr* expTmp = NULL; //待處理的節點(爲空)的父節點
Expr* expTmpLeft = NULL; //最下層的沒匹配到右括號的左括號節點
std::stack<Expr*> v_NoMatchedLLeft; //保存所有的未匹配到右括號的左括號節點
當引入賦值運算式,增加了一個賦值式根節點指針!出現等於號後,語句模式變成賦值語句——雖然沒有用標誌,但是root不爲空就表示了這是一句賦值語句——等於號分割兩個表達式,即遇到一個等於號的時候,除了把exprRoot上掛載的語法樹加到root語法樹中去之外,還要置空exprRoot表示這一表達式完整了!
/*root不爲空時語句是賦值語句,exprRoot不爲空時是表達式,root和exprRoot在構造完語法樹後不能同時爲空也不能同時不爲空*/
Expr* root = NULL; //語法樹根節點
引入賦值操作的時候,僅僅是root與exprRoot的交互,而引入判斷操作,就是judgeRoot與exprRoot的交互,只是在表達式完整的情況下,用exprRoot替換judgeRoot的位置!!!
/*judgeRoot不爲空時語句和exprRoot不爲空時語句一樣,都是表達式!!! */
Expr* judgeRoot = NULL; //判斷式語法樹根節點
項目演示
test.suatin文件內容: a = b = (1+2)*3 >= TEST_C + 5;
初始化語言環境
在初始化一些變量用於測試的位置,如果不加(std::string)修飾的話,編譯器自動推導會出錯,該位置會推導出bool類型的參數!
void InitEnv() {
/*初始化NIL , 除了傳遞NIL,傳遞其他值都不是NIL */
CreateID("NIL", false, true);
/*初始化TRUE , 0和空字符串也是TRUE, 除非傳遞NIL和FALSE,傳遞其他的值都是TRUE */
CreateID("TRUE", true, true);
/*初始化FALSE,NIL算作FALSE */
CreateID("FALSE", false, true);
/*初始化一些變量用於測試*/
CreateID("TEST_A", (std::string)"author@Demllie",true);//string
CreateID("TEST_B", 1223.23e3, true);//number
CreateID("TEST_C", 7, true);//int
CreateID("TEST_D", false, true);//bool
}
修改正則
因爲使用正則分類的時候正則從前往後進行匹配,如果某個子字符串匹配的前面的正則分組,就不會匹配後面的正則分組了!!!!
/*
註釋一定要放在最前面,至少放在/前面
數字要放到標識符前面,一定要放在點前面
>=,<=一定要放在>,<前面
==,~=,>=,<=一定要放在=前面
*/
std::string regStr = "((//.*((\n)$)?)|(/\\*(.|\n)*\\*/))|"\
"(\\d+(\\.\\d+)?(e[\\+\\-]?\\d+)?)|"\
"([a-zA-Z_]\\w*)|"\
"(\"[^\"]*\")|"\
"(\\^)|"\
"(\\*)|"\
"(\\/)|"\
"(\\+)|"\
"(\\-)|"\
"(>=)|"\
"(<=)|"\
"(>)|"\
"(<)|"\
"(~=)|"\
"(==)|"\
"(=)|"\
"(,)|"\
"(\\[)|"\
"(\\])|"\
"(\\()|"\
"(\\))|"\
"(\\{)|"\
"(\\})|"\
"(\\.)|"\
"(;)";
//\n不處理!!!
一些便於顯示的宏
宏就是隻起替換的作用,而且某些情況下還會出錯!!!某些代碼如果不寫成宏,在傳入參數時就很麻煩,要考慮不同的情況!寫成宏之後就只用傳遞進去就行,什麼類型都不會管,反正編譯器運行時會自動把使用的宏替換爲代碼!!!
//代碼轉字符串
#define CODE2STR(x) #x
//計算函數運行時間
#define SHOWFUNCTIME(str,func) \
{ \
time_t start = clock();\
func();\
std::cout <<str<< " time consumed " << clock() - start << " ms \n";\
}
//標識符最多隻能有200個
#define MAX_ID_NUM 200
//布爾轉字符串
#define BOOL2STR(x) (x?"true":"false")
//變量類型的枚舉轉字符串
#define IDTYPE2STR(x) (x==0?"nil":( x==1?"int":(x==2?"bool":(x==3?"number":(x==4?"string":(x==5?"function":(x==6?"array":"other"))))) ))
根據IDTYPE排序Map(語言環境)
void PrintEnvInfo() {
//map根據屬性type進行排序
auto compare = [](const std::pair<std::string, SuatinID*>& _arr1, const std::pair<std::string, SuatinID*>& _arr2) {
return _arr1.second->type < _arr2.second->type;
};
//map是不能排序的,內容是無序的,所以只能用別的容器來排序!!!
std::vector< std::pair<std::string, SuatinID*>> v_forSortMap;
for (std::map<std::string, SuatinID*>::iterator it = SuatinEnv.begin(); it != SuatinEnv.end(); ++it) {
v_forSortMap.push_back(std::make_pair((*it).first, (*it).second));
}
sort(v_forSortMap.begin(), v_forSortMap.end(),compare);//vector排序
//打印信息
std::cout << "語言環境>";
std::cout << "\n name isconst type funcPtr flag num str" << std::endl;
//for (std::map<std::string, SuatinID*>::iterator it = SuatinEnv.begin();it!=SuatinEnv.end(); ++it) {
for(std::vector< std::pair<std::string, SuatinID*>>::iterator it=v_forSortMap.begin();it!=v_forSortMap.end();++it){
std::cout<<std::setw(20)
<<std::right
<< (*it).first
<< std::setw(8) << BOOL2STR( (*it).second->isconst)
<< std::setw(10) << IDTYPE2STR( (*it).second->type)
<< std::setw(13) << (*it).second->value.funcPtr
<< std::setw(9) << BOOL2STR((*it).second->value.flag)
<< std::setw(16) << (*it).second->value.num
<<" " <<std::setw(30)
<<std::left
<< (*it).second->value.str //除了string左對齊外,其他都右對齊
<< std::endl;
}
}
顯示結果
詞法分析 time consumed 140 ms
中綴表達式>
name pos type keyword
a 0 10 0
= 1 23 0
b 2 10 0
= 3 23 0
( 4 27 0
1 5 7 0
+ 6 15 0
2 7 7 0
) 8 28 0
* 9 13 0
3 10 7 0
>= 11 17 0
TEST_C 12 10 0
+ 13 15 0
5 14 7 0
; 15 32 0
全局中綴表達式 time consumed 669 ms
初始化語言環境 time consumed 2 ms
語法分析·構造語法樹 time consumed 1 ms
------------------------------------------------------------
=
├── a
└── =
├── b
└── >=
├── *
│ ├── ()
│ │ └── +
│ │ ├── 1
│ │ └── 2
│ └── 3
└── +
├── TEST_C
└── 5
------------------------------------------------------------
語法分析·顯示語法樹 time consumed 55 ms
語法樹是否完全==>true
result = false
語法分析·解釋語法樹 time consumed 6 ms
語言環境>
name isconst type funcPtr flag num str
NIL true nil 00000000 false 0
TEST_C true int 00000000 true 7
FALSE true bool 00000000 false 0
TEST_D true bool 00000000 false 0
TRUE true bool 00000000 true 0
a false bool 00000000 false 0
b false bool 00000000 false 0
TEST_B true number 00000000 true 1.22323e+06
TEST_A true string 00000000 true 0 author@Demllie
顯示環境信息 time consumed 263 ms
項目代碼地址CSDN
https://download.csdn.net/download/weixin_41374099/12197890
項目代碼地址BDWP
鏈接:https://pan.baidu.com/s/1rZGGQj6IinTpjZ-yLQUyeA
提取碼:vy2a