您可能已经熟悉一门或多门编程语言。但您是否想过如何创建自己的编程语言?我的意思是:
编程语言是一套将字符串转换为各种机器码输出的规则集合。
简而言之,编程语言只是一组预定义的规则。为了使其有用,您需要一些能够理解这些规则的东西,例如编译器、解释器等。因此,我们可以简单地定义一些规则,然后,为了使其工作,我们可以使用任何现有的编程语言来编写一个能够理解这些规则的程序,这将成为我们的解释器。
编译器将代码转换为处理器可以执行的机器码(例如 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 Unknown token: ${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中文网其他相关文章!