你曾经想过创建自己的编程语言吗?在本文中,我将演示如何使用免费工具和PEG.js解析器生成器快速编写编译为JavaScript的简单语言。

什么是解析器生成器

解析器生成器顾名思义就是一个基于语法、语言规范为程序员生成解析器的程序。用特定的语法写成。在本文中,我们将使用PEG.js解析器生成器,该生成器生成一个JavaScript文件,该文件将解析语言的代码并输出AST。

什么是AST

AST是抽象语法树的缩写。这是以工具可以理解的格式表示代码的方式。我们将使用Esprima格式的AST,这是一个输出AST的JavaScript解析器。

JavaScript代码生成

Esprima语法很酷的是,有一些工具可以根据他们的AST生成代码。一个例子是escodegen,它以Esprima AST作为输入和输出JavaScript代码。

简单PEG.js解析器示例

在这里,我将展示如何为 if 语句创建简单的解析器语法。

PEG.js的语法并不复杂,它由规则的名称组成,而不是从规则中执行和返回的JavaScript的匹配和块。

以下是PEG.js文档提供的简单示例:

{ function makeInteger(o) { return parseInt(o.join(""), 10); }} start = additiveadditive = left:multiplicative "+" right:additive { return left + right; } / multiplicativemultiplicative = left:primary "*" right:multiplicative { return left * right; } / primary primary = integer / "(" additive:additive ")" { return additive; }integer "integer" = digits:[0-9]+ { return makeInteger(digits); }

它可以解析和计算简单的算术表达式示例是

10+2*3

,它计算到16。可以在PEG.js在线工具上测试此解析器。

但是我们需要的不是解释代码,返回一个值,而是返回Esprima AST。要查看Esprima AST的外观,可以检查AST资源管理器,选择Esprima作为输出并键入一些JavaScript。

下面以这样的简单代码为例:

if (foo == "bar") { 10 + 10 10 * 20}

JSON格式的输出如下:

{ "type": "Program", "body": [ { "type": "IfStatement", "test": { "type": "BinaryExpression", "operator": "==", "left": { "type": "Identifier", "name": "foo", "range": [ 4, 7 ] }, "right": { "type": "Literal", "value": "bar", "raw": "\"bar\"", "range": [ 11, 16 ] }, "range": [ 4, 16 ] }, "consequent": { "type": "BlockStatement", "body": [ { "type": "ExpressionStatement", "expression": { "type": "BinaryExpression", "operator": "+", "left": { "type": "Literal", "value": 10, "raw": "10", "range": [ 23, 25 ] }, "right": { "type": "Literal", "value": 10, "raw": "10", "range": [ 28, 30 ] }, "range": [ 23, 30 ] }, "range": [ 23, 30 ] }, { "type": "ExpressionStatement", "expression": { "type": "BinaryExpression", "operator": "*", "left": { "type": "Literal", "value": 10, "raw": "10", "range": [ 34, 36 ] }, "right": { "type": "Literal", "value": 20, "raw": "20", "range": [ 39, 41 ] }, "range": [ 34, 41 ] }, "range": [ 34, 41 ] } ], "range": [ 18, 43 ] }, "alternate": null, "range": [ 0, 43 ] } ], "sourceType": "module", "range": [ 0, 43 ]}

你不需要关心“范围”和“原始”。解析器输出的部分。

让我们把JSON分成它的一部分:

if语句

if语句需要格式:

{ "type": "IfStatement", "test": { }, "consequent": { }, "alternate": null}

其中“测试”和“后果”是任何表达式:

if语句条件

条件可以是任何表达式,但在这里我们将有一个二进制表达式,可以比较两件事:

{ "type": "BinaryExpression", "operator": "==", "left": {}, "right": {}}

变量

变量使用率如下:

{ "type": "Identifier", "name": "foo"}

字面字符串

我们代码中使用的字面字符串如下:

{ "type": "Literal", "value": "bar"}

用支架块

if里面的块是这样的创建:

{ "type": "BlockStatement", "body": [ ]}

整个程序

而整个程序都是这样创建的:

{ "type": "Program", "body": [ ]}

PEG 解析器,用于编译为 JavaScript 的自己的语言

对于我们的演示语言,我们将创建类似于这样的代码:

if foo = "bar" then 10 + 10 10 * 20end

我们将创建 AST,然后创建 JavaScript 代码。

if的语法如下所示:

if = "if" _ expression:(comparison / expression) _ "then" body:(statements / _) _ "end" { return { "type": "IfStatement", "test": expression, "consequent": { "type": "BlockStatement", "body": body }, "alternate": null };}

我们有“if”令牌,那么比较或表达式,正文是语句或空格。

比较看起来是这样的:

comparison = _ left:expression _ "==" _ right:expression _ { return { "type": "BinaryExpression", "operator": "==", "left": left, "right": right };}

表达是这样的:

expression = expression:(variable / literal) { return expression; }

变量由三条规则创建:

variable = !keywords variable:name { return { "type": "Identifier", "name": variable }} keywords = "if" / "then" / "end" name = [A-Z_$a-z][A-Z_a-z0-9]* { return text(); }

现在我们来看下语句:

statements = _ head:(if / expression_statement) _ tail:(!"end" _ (if / expression_statement))* { return [head].concat(tail.map(function(element) { return element[2]; })); } expression_statement = expression:expression { return { "type": "ExpressionStatement", "expression": expression };}

最后一件事是字面意思:

literal = value:(string / Integer) { return {"type": "Literal", "value": value };} string = "\"" ([^"] / "\\\\\"")* "\"" { return JSON.parse(text());}Integer "integer" = _ [0-9]+ { return parseInt(text(), 10); }

这就是生成 AST 的整个解析器。在我们有了Esprima AST后,我们要做的就是使用escodegen生成代码。

生成 AST 并创建 JavaScript 代码的代码如下:

const ast = parser.parse(code);const js_code = escodegen.generate(ast);

解析器变量是使用PEG.js生成解析器时给出的名称。

这是我用来编写解析器的简单演示,可以使用语法,并为编译成JavaScript的自己的编程语言生成不同的语法。

解析器生成器演示

这个简单的应用程序将代码保存在LocalStorage中,如果编译时没有错误,则每次更改。因此,可以安全地使用它创建自己的语言。

好了,本文到此结束。如果对编程、计算机、程序员方面感兴趣的话,欢迎私信联系我,随时交流!点个关注,是对我莫大的鼓励!

举报/反馈

怎样创造计算机语言,如何创建编译成JavaScript的编程语言相关推荐

  1. 如何使用react-tools将jsx编译成JavaScript

    1,通过npm安装react-tools npm –g react-tools 2,通过cmd进入项目根目录执行watch命令 jsx --watch src/ build/ src路径下存放的是js ...

  2. VScode中html怎么引入js,vscode中如何使用typescript,如何自动编译成js文件

    使用vscode创建一个typescript程序 1:介绍 typescript是一个跨平台的编程语言,专门用于前端的语言,是由微软开发,在2013年6月正式发布,它是javascript的超集,扩展 ...

  3. 很多语言转换成javaScript,介绍,转载

    JavaScript起源于Netscape公司的LiveScript语言,这是一种基于对象和事件驱动的客户端脚本语言,最初的设计是为了检验HTML表单输入的正确性. 早些年,JavaScript由于其 ...

  4. JavaScript奇淫技巧:把JS编译成exe

    JavaScript奇淫技巧:把JS编译成exe 本文,介绍一种一般人不知道的技术:把JS代码编译成exe,而且不使用第三方工具,仅用系统工具完成. 第一:工具准备 编译JS代码,使用一个名为jsc. ...

  5. 转译和编译_10个有趣又能编译为JavaScript的语言,你用过哪些?

    点击上方"IT平头哥联盟",选择"置顶或者星标" 你的关注意义重大! 来源:https://www.sitepoint.com/ 现代应用相比普通的网页有不同的 ...

  6. 将DEX反编译成Java源代码

    本文翻译自:decompiling DEX into Java sourcecode 如何将Android DEX(VM字节码)文件反编译成相应的Java源代码? #1楼 参考:https://sta ...

  7. c++ eos智能合约开发_EOS智能合约开发为何编译成WebAssembly?

    许多人正试图学习如何在EOS上开发智能合约.但是,这些智能合约是由C++编写的,并编译成WebAssembly,这对大多数非c++程序员来说似乎很奇怪.因此,在深入了解EOS之前,最好先学习一些关于W ...

  8. python编译成exe速度会变快吗_python如何编译成exe

    Python 程序都是脚本的方式,一般是在解析器里运行,如果要发布出去,需要提前安装解析器才可以运行,为了在 Windows 里方便发布,只要点击一个 EXE 文件运行,并且打包所需要库文件,这样发布 ...

  9. python源代码不需要编译成什么-python需要编译么

    一个经常听见的问题,那就是:Python是解释型的语言吗?它会被编译吗?这个问题没有想象中那么好回答.和很多人认识世界一样,习惯以一个简单的模型去评判一些事物.而事实上,里面包含了很多很多的细节. 通 ...

最新文章

  1. C++字符串详解(三) 字符串的增删改
  2. BZOJ2038 : [2009国家集训队]小Z的袜子(hose)(莫队算法)
  3. FreeRTOS操作系统,在按键中断函数中恢复被挂起的任务,程序卡死的原因和解决办法...
  4. java内部类简单解析
  5. 拓端tecdat|R语言用普通最小二乘OLS,广义相加模型GAM ,样条函数进行逻辑回归LOGISTIC分类
  6. 路径中,连续多个目录分隔符不影响,仍按照一个处理
  7. Ubuntu各文件夹功能说明
  8. svg 编辑器的点击事件兼容pc端和移动端方案
  9. vendor php,使用php composer时, 如何优雅修改vendor中第三方代码
  10. c++ 序列化库iguana使用总结
  11. 利用Promise彻底解决微信小程序云函数因运行时间过长返回result,underfined为空的方法
  12. POSCMS 城市三联动回显(自定义)
  13. 持续集成与持续部署(五)01-TravisCI——使用简介-Travis CI 只支持 Github,提供的是持续集成服务 配置项目的.travis.yml文件
  14. My blog has been migrated to GitHub.
  15. 【Java 并发编程】我们为什么要学并发编程?
  16. 模拟POST、Get 请求的工具----APIpost(中文版POSTMAN)
  17. Checkra1n越狱更新0.12.4版本,支持iOS14.7.1越狱
  18. [Asp.Net Core]NET5跨平台的本质
  19. docker 删除映像_创建自己的Docker映像(技术提示#57)
  20. python gil全局锁_什么是Python全局解释器锁(GIL)?

热门文章

  1. UE5废墟破坏游戏场景创建学习教程
  2. linux open系统调用的O_DIRECT标记
  3. LeetCode 1021:Remove Outermost Parentheses
  4. ubuntu 使用阿里云 apt 源
  5. CentOS 6.7快速搭建lamp环境
  6. mybatis批量更新的两种实现方式
  7. 某大型银行深化系统之二十:异常规范
  8. Linux抓包工具tcpdump详解
  9. HDU2673-shǎ崽(水题)
  10. 大型网站采用什么系统架构保证性能稳定性