尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

我写了一门编程语言,你也可以!

我写了一门编程语言,你也可以! 过去六个月里我始终在专注于开展对一门名为 的编程语言的开发工作。我没办法讲它已然臻于成熟然而它在实际运用当中已然具备了相当数量编程语言的特性, 诸如:要是你存有那份兴致, 那就去瞅瞅其引导页, 也就是page, 或者去瞧瞧它的repo哟。我并非是个专家, 在开启这项工程之时, 我对于自己所从事之事尚无明确方向, 然而我依旧未曾选择放弃, 我于语言 创建方面级别处于0的状态, 仅仅少量阅读了一些在线信息, 且并未依照我所给出的那些建议标点。然而, 我终究还是创新性地缔造了一门全然完整的崭新语言。而且它具备能够正常运行的能力。因而我必定是做了正确无误的事情。于这篇文章当中, 我会深度详尽地展示, 以及其他各类编程语言把源码转变成新语主儿言的进程。我同样还会述说一番我已然做出的某些权衡考量, 以及缘何我会做出那些抉择的缘由。这绝非是制作编程语言的整部教程, 然而要是你对语言开发存有好奇之心, 那么这算得上是一个不错的起始点。入门当我跟其他开发人员讲我在写一门语言时, 通常会得到这样的回应, “我都不知道我该从哪里进行起始”。如此, 在听后的现象是这样的反应情况下, 如果也是这样, 那我现在要经过一些已经曾经尝试过的做下决策做的事和采取行动, 来对你讲述怎样开启一门创新语言。编译型 vs 解释型语言主要有两种类型编译型和解释型编译器能够算出来一个程序会执行的操作, 把它转化成“机器代码”, 这是计算机能够运行的那种格式速度极其快, 之后存起来用于后面执行。一个解释器逐行逐步执行源代码弄清楚它在做什么。在技术层面, 无论何种语言, 皆是能够被编译或者解释的, 然而, 对于特定的语言来讲, 一般情况下, 一种语言或是另外一种语言反而更具意义。正常而言, 解释通常会显得较为 巧妙灵活, 而编译往往具备更高的效能, 可这实则也只是在处理复杂问题之前的一种如微微烧热般的准备状态罢了。我对性能予以高度重视, 我看见了存在缺乏高性能以及简单性情况的编程语言, 因此我前去执行编译了。这是一项重要决定此决定需要在今早予以确定, 因为它会影响相当多的语言设计决策举例来讲, 静态类型对于编译型语言而言属于极大的裨益, 然而对解释型语言来讲其重要程度并非如此。即便 其是基于编译型进行设计塑造, 然而它竟存在那样一个独此一家可投入运行的, 各项功能全然完备的解释器。至于原因, 不多时为那各位阐释一下。选择一门语言这有点类似那种元数据, 我是清楚的, 鉴于编程语言自身就是个程序之类东西, 所以编写它得选一种语言写才行, 选用了哪一种语言, 选的是C , 为啥选它, 是因为它有那般性能以及庞大的功能集合一块儿这双方面相关缘故, 除此之外, 实际上我是偏喜欢运用这种C 来开展工作的。要是你正着手编写一种解释性语言, 那于编译语言像C、C 或者Swift里编写会极具意义, 鉴于你那解释型语言之中的性能损耗以及与之对应的解释器会更为复杂。若你计划进行编译, 那种速度较慢的语言比方说这样的像这种或者Java是更可以被接受的, 编译花费的时间或会很不理想, 然而于我所认为的观点里, 运行所耗的时间差异并非很大。高级设计一类管线通常被构造为一门编程语言, 也就是说, 它通常拥有几个阶段, 每个阶段的数据都会以明确的方式格式化, 并且还具有将数据从这一阶段转换到下一个阶段的功能。一串包含整个输入源文件的字符串属于第一个阶段。可以被运行的东西, 正是最终阶段。当我们逐步去完成管线时候, 这一切就会清晰起来。词法第一步, 对于大多数编程语言而言的, 是词法分析法, 或者是分词这一操作。“Lex”, 它可是词法分析的缩写, 无疑是一个相当出色的那种词, 其作用在于把数量众多的文本给分解成好多符号。“”这个词, 有着更丰富的意义, 然而, “词法分析”这个表述讲起来是蛮有意思的, 所以, 在平常我常常会去使用它。标记是语言的一个单元的叫标记或记号, 标记里头, 有可能是变成变量或者函数名的那种东西, 也就是标识符, 又或者, 是一个操作符, 还有可能, 是一个数字。词法分析器的任务词法分析器把包含源码的文件当作输入字符串, 进而输出含有标记符号的列表。编译过程中的流水线后面阶段, 不会再去参考那些字符串源代码中的信息, 所以词法分析器得产生后面各阶段所需的全部信息。存在这样相对严格格式设计的缘由在于, 此阶段词法分析器能够开展一些工作, 像是移除注释、检测标识符或者数字之类的。要是把这些逻辑规则放置在词法分析器里, 那么在构建语言其他部分的时候就无需再去考量这些规则了, 并且能够方便在同一处地点集中更改这些语法规则。Flex开始着手开发这个语言时, 我做的头一件事便是去写一个简易的词法。没过多久, 我着手投入到学习能使词法变得更为简单及正确的工具之中。有个小工具名为 Flex, 那是个能生成词法的程序。你把一份用特定格式去描述语言语法的文件作为输入传进去。接着它便能生成一段C语言语法架构的程序代码啦。我的决定我做出了暂时保留最初所写的词法分类器的选择, 因为直至最后我都未曾看到 Flex 的显著优势, 至少无法达成添加依赖以及完成复杂构建这一情况。我的那个进行词法分类的工具, 代码行数也就几百行而已, 基本上没什么差错。对我的这个词法分类器进行迭代操作, 也赋予了更多的灵活特性。就好比, 在不针对多个文件实施编辑动作的情形下, 给语言增添操作符。语法分析管线流程的第二阶段居然是语法分析器, 语法分析器会将标识符列表解析成一个带有结点的树, 用于储存这类数据的树被称作抽象语法树, 也就是AST, 最后在那抽象语法树里不会含有任何标识符类型信息, 它只是一个简单的结构化的标识符。解析器的作用结构被解析器添加到, 词法分析器所产生的, 有序列表里的令牌之中。为了去阻止歧义, 解析器必定要考虑括号以及操作顺序。简单的解析运算符并非十分困难, 然而随着更多语言结构被添加, 解析就变得极为复杂。Bison再有, 存在一个决定关联第三方库, 其中主要的解析库是什么, 是Bison, Bison的作品与Flex很相像, 用什么编写那存储语法信息的自定义格式文件, 要用就你的自定义格式去编写文件之后干什么, 之后Bison会利用该文件生成会执行解析的C程序, 但我没选择去用Bison。为什么自定义更好在词法分析器里头, 拿来用我个人的代码, 这可是个显而易见的抉择。词法分析器它是那种小程序, 要是我自己不去编写, 那就好似不会去编写我自身的“left - pad”那般愚笨。解析器属于另外一种情况, 我的解析器当前长度为750线, 我编写了三个, 原因是前面两个都不行。由我来做出这般的决定, 缘由存在着诸多, 虽说并非顺顺当当, 然而其中的大半都是正确无误的, 主要所涵盖的内容是为此:在起始之时, 我并非全然确切知晓这究竟能不能行, 然而, 对于那C 早期版本的开发人员, D 语言的创造者, 我所要讲的是:更具争议的一点是, 我不会在词法分析器或解析器生成器以及其他所谓的“编译器的编译器”上浪费时间, 因为这么做太浪费时间了。编写词法分析器和解析器只是编写编译器工作中的一小部分。使用生成器所花费的时间与手工编写一样多, 并且在将编译器移植到新平台时, 它还会与生成器相结合这一点很重要。生成器有时还会发出糟糕的错误信息以及不幸的声音。行为树 Tree现在, 我们已然离开了存在共同术语或者通用术语的领域, 起码这些术语我并不认识。就我的理解而言, 我所说的‘行动树’, 是最为类似于LLVM的IR中间表示的。我耗费了一段颇为绵长的时间才弄明白, 存在着一种细小然而极为关键的差异置身于行为树与抽象语法树之间, 我们务必要予以区别看待, 正是这一情况促成了解析器的改写。行为树 vs AST简单来讲, 行为树是有着上下文的AST, 上下文是一种函数返回的类型方面的信息, 或者是两个地方所运用的变量实则为同一个变量, 由于它得弄明白并记住所有这些上下文, 所以生成行为树的代码就需要大量的命名空间查找表以及其他之类的事物。运行行为树有了行为树之后, 运行代码变成极易之事。每个行为节点, 存着一个函数, 此函数有接受一些输入之能, 无论行为怎样, 哪怕包含或许调用子行为的情况, 皆会返回行为的输出。这个, 便是行为里的解释器。编译的选择等等, 难道不是应当先进行编译吗, 嗯, 没错, 然而编译起来相较于解释可要复杂得多, 存在着几种解决方案。新开发一个编译器听起来这是个挺不错的办法, 我有着创造事物的喜好之情, 早早之前就萌生想着认认真真去研究那编译领域了呢。但是, 编写一个编译器并非只是把语言的每个元素都翻转为机器代码这般简易, 由于存在诸多不同的架构以及操作系统, 所以个人要去编写一个能跨越多个平台的编译器是不具实际可行性的。即便是 Swift 团队的 Rust, 以及 Clang, 这二者也都不想从起始之处开始进行编写, 他们所采用的办法是。LLVMLLVM 是个编译工具集, 本质上近乎是个库, 它能将你的编程语言编译成可执行文件, 看上去好像是绝佳的选择, 故而我即刻就采用了它, 然而很不幸, 当时并没有察觉到其中的复杂程度究竟有多深。LLVM, 就算没汇编语言那般难, 也是个异常庞大的库, 几乎难以使用。即便他们有很不错的帮助文档, 可我觉着在全力运用LLVM予以实现之前, 我还得多积攒些经验, 像这样。转译我想快速编译 所以我转向了一种可行的方法转译。我撰写了一个, 将其做成到C的转译器, 并且增添了运用GCC自动编译以输出源码的功能。这个于当下适用于差不多所有程序, 不过存在例外情况。它并非是一种特别便于携带或者能够扩展的解决办法, 然而却是一种可用来应急的临时解决办法。未来假设这般接下来还予以开发 ,迟早而言它会获得 LLVM 的编译方面的支撑。对不管我开展了多少的工作这件事持有怀疑态度 ,转译器始终都不会处于完全稳定运行的状态 ,而 LLVM 所具备的益处有好多。问题在于何时情况下我才能够拥有时间于 LLVM 当中去搞一些示例项目 ,并且还能熟练掌握它。在此之前, 解释器对 tiny 程序而言相当不错, 而且 C 转译在多数需更多性能之际适用。结论所编写的编程语言, 我期望其于你而言简单清晰, 若你欲自行制作一个, 我大力举荐它, 尚有诸多实现细节有待明晰, 此处大纲对之作辅助。这, 乃是我所给出的入门方面的 要记住哟, 我实实在在地不清楚我所进行的是什么, 因而仅仅是列举出一个示例而已:深感抱歉, 在实现进程当中, 我采取了一些并不明智的抉择, 不过, 我已然将大部分受此错误波及的代码予以重新编写了。此时此刻, 已然是足够良好的状态了, 尤其值得一提的是其具备的功能, 这能够接纳进一步的改良。进行编写, 于我而言那是一段极富获益且充满快感的经历, 而这仅仅只是刚刚开启的阶段。本文系开源中国授权发布如需转载请与开源中国公众号联系
返回列表