Kaleidoscope: Tutrial Introduction and the Lexer

Kaleidoscope: Tutorial Introduction and the Lexer

Basic Language

Kaleidoscope

使用Kaleidoscope作爲玩具語言,我們可以定義函數,使用條件,數學等.
唯一的數據類型是64位浮點類型(C語言中稱爲"double"),並且不需要類型聲明,語法簡單.
以計算Fibonacci數爲例:

def fib(x)
	if x < 3 then
		1
	else
		fib(x-1) + fib(x-2)

Kaleidoscope可以調用標準庫函數,可以使用"extern"來定義函數,如:

extern sin(arg)
extern cos(arg)
extern atan2(arg1 arg2)

atan2(sin(.4), cos(42))

The Lexer 詞法分析器

在實現一種語言時,首先需要處理文本文件並識別它所說內容.使用詞法分析器將輸入分解爲"tokens", 詞法分析器返回的token包括一個標記代碼和可能的一些元數據.首先,我們定義了可能的值:

//如果是未知字符, 詞法分析器返回標記[0-255], 否則的話以下值之一會被返回
enum Token{
	tok_eof = -1,
	
	//commands
	tok_def = -2,
	tok_extern = -3,
	
	//primary
	tok_identifier = -4,
	tok_number = -5,
};

static std::string IdentifierStr; //如果是tok_identifer, 填寫
static double NumVal;           //如果是tok_number, 填寫

詞法分析器返回的token是Token枚舉值之一,或者,‘未知’字符的話, 如’+’,將返回ASCII值. 如果當前token是標識符, 則IdentifierStr全局變量保存其名稱. 如果是一個數值字符,如(1.0), 則NumVal保存其值.
詞法分析器實際實現爲gettok函數,當從標準輸入返回下一個標記時, gettok被調用. 它的定義爲:

static int gettok(){
	static int LastChar = ' ';
	
	//跳過空格
	while (isspace(LastChar))
		LastChar = getchar();
}

接下來, gettok需要做的是識別標識符和關鍵字,如’def’. IdenfitifierStr設置爲全局,使用下面循環實現:

if (isalpha(LastChar)){   // identifer: [a-zA-Z][a-zA-Z0-9]*
	IdentiferStr = LastChar;
	while (isalnum((LastChar = getchar())))
		IdentifierStr += LastChar;

	if (IdentifierStr == "def")
		return tol_def;
	if (IdentiferStr == "extern")
		return tok_extern;
	return tok_identifier;
}

對於數值的處理類似:

if (isdigit(LastChar) || LastChar == '.'){  // Number: [0-9.] +
	std::string NumStr;
	do {
		NumStr += LastChar;
		LastChar = getchar();
	} while (isdigit(LastChar) || LastChar =='.');
	
	NumVal = strtod(NumStr.c_str(), 0); //strtod將字符串轉換爲浮點數值
	return tok_number;
}

其中, c_str()函數返回一個指向正規C字符串的指針, 內容與本string串相同.這是爲了與c語言兼容,在c語言中沒有string類型,故必須通過string類對象的成員函數c_str()把string 對象轉換成c中的字符串樣式其中,.
接下來我們處理註釋, 通過調到行尾來處理,然後返回下一個token.:

if (LastChar == '#') {
	//處理到行尾的註釋
	do
		LastChar = getchar();
	while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); //\r是回車

	if (LastChar != EOF)
		return gettok();
}

最後,如果輸入與上述情況之一不匹配,則它是像’+'這樣的運算符或者文件結尾,可以使用以下代碼處理:

// 檢查是否文件結尾,保留EOF
if (LastChar == EOF)
	return tok_eof;

// 否則,直接返回其ascii值
int ThisChar = LastChar;
LastChar = getchar();
return ThisChar;

到此,一個基本的Kaleidoscope語言的完整詞法分析器就完成了.

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