您可能已經熟悉一門或多門編程語言。但您是否想過如何創建自己的編程語言?我的意思是:
編程語言是一套將字符串轉換為各種機器碼輸出的規則集合。
簡而言之,編程語言只是一組預定義的規則。為了使其有用,您需要一些能夠理解這些規則的東西,例如編譯器、解釋器等。因此,我們可以簡單地定義一些規則,然後,為了使其工作,我們可以使用任何現有的編程語言來編寫一個能夠理解這些規則的程序,這將成為我們的解釋器。
編譯器將代碼轉換為處理器可以執行的機器碼(例如C 編譯器)。
解釋器逐行遍歷程序並執行每個命令。
想嘗試一下嗎?讓我們一起創建一個超簡單的編程語言,它在控制台中輸出品紅色輸出。我們將其稱為Magenta 。
我將使用Node.js,但您可以使用任何語言來學習,概念保持不變。讓我首先創建一個index.js 文件並進行設置。
class Magenta { constructor(codes) { this.codes = codes; } run() { console.log(this.codes); } } // 目前,我們將代碼存儲在一個名為`codes` 的字符串變量中// 稍後,我們將從文件中讀取代碼const codes = `print "hello world" print "hello again"`; const magenta = new Magenta(codes); magenta.run();
我們在這裡做的是聲明一個名為Magenta 的類。該類定義並初始化一個對象,該對象負責使用我們通過codes 變量提供的任何文本將文本記錄到控制台。並且,目前,我們已在文件中直接使用幾個“hello”消息定義了該codes 變量。
好的,現在我們需要創建一個所謂的詞法分析器。
好的,讓我們先談談英語。請看以下短語:
你好嗎?
這裡,“你好”是問候語,“嗎”是語氣助詞,“你”是人稱代詞。我們還有一個問號(“?”)在結尾。我們可以像這樣將任何句子或短語劃分為許多語法成分。我們區分這些部分的另一種方法是將它們劃分為小的標記。將文本劃分為標記的程序是我們的詞法分析器。
由於我們的語言非常小,它只有兩種類型的標記,每種都有一個值:
我們可以使用正則表達式從codes 字符串中提取標記,但性能會非常慢。更好的方法是循環遍歷代碼字符串的每個字符並獲取標記。因此,讓我們在Magenta 類中創建一個tokenize 方法——這將是我們的詞法分析器。
完整代碼
`` javascript class Magenta { constructor(codes) { this.codes = codes; } tokenize() { const length = this.codes.length; // pos 用于跟踪当前位置/索引let pos = 0; let tokens = []; const BUILT_IN_KEYWORDS = ["print"]; // 变量/关键字允许的字符const varChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"; while (pos : ${word} <code>); } } return tokens; } parse(tokens) { const len = tokens.length; let pos = 0; while (pos Unexpected token: ${token.type}`); } } } run() { const tokens = this.tokenize(); this.parse(tokens); } }
const codes = print "hello world" print "hello again"
; const magenta = new Magenta(codes); magenta.run();
### 定義規則和語法我們想看看我們的代碼順序是否與某種規則或語法相匹配。但首先我們需要定義這些規則和語法是什麼。由於我們的語言非常小,它只有一個簡單的語法,即print 關鍵字後跟一個字符串。
關鍵字:打印字符串
<code>因此,让我们创建一个解析方法,该方法循环遍历我们的标记,并查看我们是否形成了有效的语法。如果是这样,它将采取必要的措施。 ```javascript class Magenta { constructor(codes) { this.codes = codes; } tokenize() { /* tokenizer 的先前代码*/ } parse(tokens) { const len = tokens.length; let pos = 0; while (pos </code>
瞧!我們已經有了一種工作的語言了!
好的,但是將代碼放在字符串變量中並沒有那麼有趣。因此,讓我們將我們的Magenta代碼放在一個名為code.m 的文件中。這樣,我們可以將magenta 代碼與編譯器邏輯分開。我們使用.m 作為文件擴展名來表示該文件包含我們語言的代碼。
讓我們從該文件中讀取代碼:
// 導入文件系統模塊const fs = require('fs'); // 導入路徑模塊以方便路徑連接const path = require('path'); class Magenta { constructor(codes) { this.codes = codes; } tokenize() { /* tokenizer 的先前代碼*/ } parse(tokens) { /* parse 方法的先前代碼*/ } run() { /* run 方法的先前代碼*/ } } // 讀取code.m 文件// 一些文本編輯器使用\r\n 作為換行符而不是\n,因此我們刪除\r const codes = fs .readFileSync(path.join(__dirname, 'code.m'), 'utf8') .toString() .replace(/\r/g, ""); const magenta = new Magenta(codes); magenta.run();
就這樣,我們已經成功地從頭開始創建了一個微型編程語言。看,編程語言可以像完成一件特定事情一樣簡單。當然,像這裡的Magenta 這樣的語言不太可能有用到成為流行框架的一部分,但現在您已經了解了創建編程語言需要什麼。
天空才是極限。如果您想更深入地研究,請嘗試按照我製作的視頻進行操作,該視頻介紹了一個更高級的示例。在這個視頻中,我還展示瞭如何向您的語言添加變量。
以上是讓我們創建一種小型編程語言的詳細內容。更多資訊請關注PHP中文網其他相關文章!