教你使用swift寫編譯器玩具(1)

前言

本章對應官方教程第1章,介紹了Kaleidoscope以及實現詞法分析器(Lexer)html

教程以下:git

教你使用swift寫編譯器玩具(0)github

教你使用swift寫編譯器玩具(1)swift

教你使用swift寫編譯器玩具(2)bash

教你使用swift寫編譯器玩具(3)app

教你使用swift寫編譯器玩具(4)ide

教你使用swift寫編譯器玩具(5)函數

教你使用swift寫編譯器玩具(6)post

教你使用swift寫編譯器玩具(7)this

教你使用swift寫編譯器玩具(8)

倉庫在這

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用來表示當前正在解析的內容。

定義Lexer

在編寫詳細的token處理以前,咱們須要先定義一下Lexer類。

class Lexer {
    
    /// 當前的token
    public var currentToken: CurrentToken?
    
    private var lastChar: Character = " "
    
    private var index = 0
    
    /// 代碼內容
    private var source: [Character] = []
    
}
複製代碼

本工程解析代碼經過index的增長從而依次從source中讀取每個字符進行處理。

獲取下一個token

獲取當前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了。

相關文章
相關標籤/搜索