lang:談談自制編程語言1

前言

目前很有野心,打算做個大事。雖然編程水平還不高,看《編譯原理》也看不下去,看視頻教程看了十幾節課發現筆記上全是數學符號。就——暫時不看了吧!我之前因爲好奇買了本《兩週自制腳本語言》,的確學了一些知識。但是其中從第五天開始,都使用了一個Parser庫,看知乎知道了難點不在這個庫上,所以一般都用現成的。而書的問題是代碼沒多少註釋!!!實在搞不明白,再加上java用起來實在不爽!於是這條路也拋棄了,最後我打算先從一箇中綴表達式轉後綴表達式搞起——因爲機器識別不了式子,只能識別符號和數字,所以可以先轉換成後綴表達式,然後通過這個表達式求解。

一般在語法分析的時候,需要構造AST語法樹。而中後綴這條路不用,需要利用

形成語法樹可以把各種符號涵蓋進去,而中後綴只能計算數字直接的加、減、乘、除、乘方等簡單的一元或二元操作,最後也只能得到一個計算結果(一般是double類型的數)。

我覺得中後綴這條路挺好用的,凡是表達式都可以用這種方法得到結果,如果有函數在其中,就把函數替換爲函數的返回結果!

雖然這麼說!但是這只是對錶達式而言!對於其他語句和語句塊,還是要構造AST的!

我目前的項目進度到了分割語句和分類語句上,已經完成了分割Token和分類Token,因爲項目中變化太多,加上現在已經有了31個文件,實在沒辦法放上來。但是可以把一些概念貼上!

上層語言與下層語言的關係

上層語言是我的自制語言Suatin-lang,下層語言是C++。
上層語言方法都是小寫,下層語言方法大部分都是駝峯

上層語言的類型,如int/number/BigNumber/complex/string/bool/function/array/file都繼承於object,不是因爲我想搞面向對象和高階函數什麼的,而是這樣後面創建對象和傳遞對象時比較方便!!!

下層語言C++中有對應的類,如SuaInt/SuaNumber/SuaBigNumber/SuaComplex/SuaString/SuaFunction/SuaBool/SuaArray/SuaFile/SuaObject,這些類專門對應着處理上層語言的數據對象——變量、函數等。

//SuaUtil.h
class SuaObject {
protected:
	bool isconst = false;///是否是常量。const可以修飾SuaObject
	std::string name="";///標識符名稱
	int zoneIndex;//作用域索引,和pos一起用的。只有SuaObject纔有這個

public:
	//返回類型名的字符串,因爲源碼是字符串,輸入輸出都是字符串處理
	virtual std::string getname()const = 0;

	//返回類型
	virtual std::string gettype()const = 0;



	///常量操作
	bool is_constant()const;
	void setconst();
	void resetconst();

};

解釋器中的類

下層語言還有其他的類,如Token。源碼中所有的符號被分類,每個符號或標識符都放入一個Token,所有的Token都會放入全局的容器中,即放入全局中綴表達式中。特殊的Token會包含SuaObject對象——即自定義變量或函數。

Expr——只有四則加乘方的運算才能算作表達式,這個我還沒認真修改。只有個空殼。表達式裏關鍵是兩個變量,start&end,表示表達式在全局中綴表達式的中範圍。

Pool——存儲池,自定義的變量或函數,即SuaObject對象,會放入這個池子裏。暫時不想搞類型推導,所以暫時打算做靜態類型的語言。每次遇到一個標識符都會和池子裏的進行比對,看看池子裏是否有。檢查標識符靠的是標識符的名稱,不是地址。

在上層語言中,一個變量或函數只有兩個關鍵的點,一是它的值,放在底層的SuaObject中。二是它字符串的名稱,這意味着在此上層語言中,不能對關鍵字創建變量!!!

Parser——用來遍歷中綴表達式,分割語句和分類語句。其中有幾個關鍵變量:start&end&三個作用域計數器&作用域容器。

  • start&end從頭開始遍歷到尾,來分割不同的語句。
  • 作用域計數器就厲害了。每遇到一個左括號就加一,遇到右括號就減一,即當計數爲n時的位置是A時,再到了計數爲n-1的位置爲B後,A-B之間就是一個作用域!!!識別不同作用域靠n的值。
  • 三個作用域計數器就是三個int,分別計數小括號、中括號、大括號。
  • 作用域容器放一個結構體,用來表示一個作用域。內容是作用域索引、作用域開頭、作用域結尾。每個SuaObject內存放一個自己的作用域索引,Token中有該符號的位置,把位置和索引都傳入Parser的作用域檢測方法,就能知道此變量是否在該作用域內
  • 但是當兩個作用域並行時,他們的索引是一樣的,所以需要再引入一個變量number。區分並行的作用域!
//Parser.h
//這個類暫時的樣子
class Parser
{
private:
	//一個語句的起始就是start到end-1
	int start;//語句開頭,可以是標識符、數字
	int end;//語句結尾,可以是\ n   ;   }    {
	//一個作用域的起始就是count_zoneQ_xxx=n到count_zoneQ_xxx=n-1時,對應的兩個位置之間
	//下面三個計數器都是遇到左括號加一,遇到右括號減一。不同的作用域間的數不同。這個數指的就是作用域索引。
	static int count_zoneQ_little;//小括號作用域計數
	static int count_zoneQ_middle;//中括號作用域計數
	static int count_zoneQ_big;//大括號作用域計數
	

	//花括號作用域索引,在使用語句前,先經過檢查是否在對應的作用域內—— GetVal()
	//索引小的作用域大!!!所以如果是作用域1的數,可以在作用域2/3內使用
	typedef struct _ZONE{
		int index;//作用域索引
		int number;//區分並行作用域
		int start;//作用域開頭
		int end;//作用域結尾
	}ZONE;
	static std::vector<ZONE*> zone;


public:
	
	//分割語句
	static void SyntaxSeparate();
	//分類語句
	static void SyntaxClassify();

	//檢查變量的位置是否在其作用域內
	static bool InZone(int index,int number,int pos);
	

};

shell——解釋器的交互面。從文件中讀入字符串、Token的分割與分類、顯示Pool池子的內容、顯示中綴表達式的內容、顯示語句分類的內容等等直接得到處理效果或是運行效果的函數。

SuaUtil——最底層的倉庫。自定義異常處理、各種枚舉、基類的定義等等。既然是最底層的類,那麼絕對不能放太多的東西來增加依賴,應該不依賴其他自定義的文件!

SuaMath——一些數學操作的集合。
SuaExcept——自定義異常類,枚舉了一些能想到的錯誤。具體請見之前的文章lang:C++自定義異常類——用來處理自制編程語言的異常信息

文件的引用關係

項目大了要分好文件,不能有交叉引用。因爲如果後續我使用模板、友元的話會很麻煩。
在這裏插入圖片描述

解釋器的結構

目前腦子裏的解釋器是下面這樣,以後完成了肯定會不同的。

解釋器運行流程

  1. 傳入 .suatin文件的路徑,並運行解釋器。
  2. .suatin文件中讀取字符串,一行行地組成一個字符串,每讀取一行就在後面添加一個\n——也可以添加\r\n,那樣的話稍微有點不同而已
  3. 對整個字符串進行正則匹配,把關鍵字、標識符、五則運算符(+ - * / ^ )、判斷運算符(> < <= >= == ~=)、小括號、中括號、大括號、數字(含小數、指數)、註釋(含單行註釋、多行註釋)、換行\n、分號、等於號、逗號運算符都分割出來,然後得到分組索引,映射爲優先級後,除了註釋外的符號都創建Token
  4. 把Token放入全局中綴表達式中。
  5. 遍歷中綴表達式,分割語句,確定標識符(即變量、函數)作用域,把作用域信息保存到ParserSuaObject上。分類語句,把一條條的語句放入語句鏈中——放語句在中綴表達式中的範圍就行——執行代碼就是執行這條語句鏈!
  6. 根據代碼中的變量定義語句,創建SuaObject對象的實例,並把指針放入Pool池子中。
  7. 構造語法樹AST
  8. 求解語法樹

在這裏插入圖片描述
因爲是直接運行的,沒有中間代碼,所以與其說是解釋器,不如說是直譯器!

項目現在做到了那個位置?

下面是測試Suatin-lang的源碼,C++項目就省略了。

//test.suatin
int sum=0.0e0
const int i=0
string str="hello world suatin-l
	ang programmer!"
if str == null 
{ print("yes") }
else
{
	i=i+1      //zhushi
	sum=sum+i /*duohangzhushi
         */
	sum=sum/2;sum=sum+sum*i
}
print(sum+i)//zhushi

顯示結果:

welcome to suatin interpretor interface

C:\Users\LX\Desktop\test.suatin內代碼爲>
int sum=0.0e0
const int i=0
string str="hello world suatin-l
        ang programmer!"
if str == null
{ print("yes") }
else
{
        i=i+1      //zhushi
        sum=sum+i /*duohangzhushi
         */
        sum=sum/2;sum=sum+sum*i
}
print(sum+i)//zhushi
--------------代碼結束!--------------
中綴表達式>
           name     pos  priority
            int      0       1
            sum      1      12
              =      2       8
          0.0e0      3      18
             \n      4       6
          const      5       1
            int      6       1
              i      7      12
              =      8       8
              0      9      18
             \n     10       6
         string     11       1
            str     12      12
              =     13       8
        "hello world suatin-l
        ang programmer!"     14       5
             \n     15       6
             if     16       1
            str     17      12
             ==     18      11
           null     19       1
             \n     20       6
              {     21       3
          print     22      12
              (     23      10
          "yes"     24       5
              )     25      10
              }     26       4
             \n     27       6
           else     28       1
             \n     29       6
              {     30       3
             \n     31       6
              i     32      12
              =     33       8
              i     34      12
              +     35      15
              1     36      18
             \n     37       6
            sum     38      12
              =     39       8
            sum     40      12
              +     41      15
              i     42      12
             \n     43       6
            sum     44      12
              =     45       8
            sum     46      12
              /     47      14
              2     48      18
              ;     49       7
            sum     50      12
              =     51       8
            sum     52      12
              +     53      15
            sum     54      12
              *     55      14
              i     56      12
             \n     57       6
              }     58       4
             \n     59       6
          print     60      12
              (     61      10
            sum     62      12
              +     63      15
              i     64      12
              )     65      10
             \n     66       6
第1條語句>sum=0.0e0
第2條語句>i=0
第3條語句>str="hello world suatin-l
        ang programmer!"
第4條語句>str==null
第5條語句>print("yes")
第6條語句>i=i+1
第7條語句>sum=sum+i
第8條語句>sum=sum/2
第9條語句>sum=sum+sum*i
第10條語句>print(sum+i)
作用域信息>
index = 1,number=1,start=21,end=26
index = 1,number=2,start=30,end=58
請按任意鍵繼續. . .

CSDN
項目在我的資源裏(要多少C幣不是我決定的,明明設置的需要0C幣,但是之後看被改了555)!

項目代碼地址BDWP
鏈接:https://pan.baidu.com/s/1yX7j69kpbr4a5kd-V-LyRg
提取碼:2agq
複製這段內容後打開百度網盤手機App,操作更方便哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章