本章對應官方教程第1章,介紹了Kaleidoscope以及實現詞法分析器(Lexer)html
教程以下:git
教你使用swift寫編譯器玩具(0)github
教你使用swift寫編譯器玩具(1)swift
Kaleidoscope大概長這樣
def fib(x)
if x < 3 then
1
else
fib(x-1)+fib(x-2);
fib(40);
複製代碼
本項目參考官方文檔編寫,爲了圖方便與官方文檔同樣寫了很多全局變量,這在實際工程中不是一個好的處理方式。
注意:教程中使用extern調用標準庫本文並未實現,僅實現了extern的解析。
咱們在實現語言時,首先須要能識別代碼內容。一般狀況下咱們使用詞法分析器(Lexer),將輸入分解爲Token。首先咱們須要定義Token以及CurrentToken結構體。
enum Token {
case def
case extern
case identifier
case number
case other
}
struct CurrentToken {
var token: Token
var val: String
}
複製代碼
identifier是用來記錄變量,而其餘的幾個Token的枚舉一目瞭然。CurrentToken用來表示當前正在解析的內容。
在編寫詳細的token處理以前,咱們須要先定義一下Lexer類。
class Lexer {
/// 當前的token
public var currentToken: CurrentToken?
private var lastChar: Character = " "
private var index = 0
/// 代碼內容
private var source: [Character] = []
}
複製代碼
本工程解析代碼經過index的增長從而依次從source中讀取每個字符進行處理。
獲取當前index對應的字符
private func getChar() -> Character {
let char = source[index]
index += 1
return char
}
複製代碼
解析當前字符獲取下一個currentToken
/// 獲取下一個currentToken
public func nextToken() {
var identifierStr = ""
//若是是空白則繼續往下讀取
while lastChar.isWhitespace {
lastChar = getChar()
}
//若是開頭是字母的話說明是identifier類型或者是其餘關鍵字
if lastChar.isLetter {
identifierStr = String(lastChar)
lastChar = getChar()
while lastChar.isNumber || lastChar.isLetter {
identifierStr.append(lastChar)
lastChar = getChar()
}
if identifierStr == "def" {
currentToken = CurrentToken(token: .def, val: "def")
} else if identifierStr == "extern" {
currentToken = CurrentToken(token: .extern, val: "extern")
} else {
currentToken = CurrentToken(token: .identifier, val: identifierStr)
}
return
}
//是數字開頭的話說明這個是一個數值
if lastChar.isNumber || lastChar == "." {
var numStr = ""
repeat {
numStr.append(lastChar)
lastChar = getChar()
} while lastChar.isNumber || lastChar == "."
currentToken = CurrentToken(token: .number, val: numStr)
return
}
//遇到";"說明這一個函數塊結束了
let thisChar = lastChar
if thisChar != ";" {
lastChar = getChar()
}
//返回其餘類型僅做爲佔位使用
currentToken = CurrentToken(token: .other, val: String(thisChar))
}
複製代碼
代碼詳細的解釋都體如今了註釋中,如今咱們已經完成了一個能夠解析token的Lexer了。