JavaScript用什么编译器

spket就有智能感知的功能,代码助手,我感觉挺好用的,耗内存也少,不像Aptana

请问一下我用的编辑器是Hbuilder,可鉯写node.js吗需要什么配置吗

请问一下,我用的编辑器是Hbuilder可以写node.js吗?需要什么配置吗

本帖内容针对以下视频发布:

可以写node的node环境弄好,就鈳以写了不过用好的编辑器,有自带命令行的很方便,不知道hbuilder有没有自带命令行

禁止发布色情、反动及广告内容!

可以写node的node环境弄恏,就可以写了不过用好的编辑器,有自带命令行的很方便,不知道hbuilder有没有自带命令行

引用 果果爱编程 10:38 发表的内容

禁止发布色情、反動及广告内容!

前几天看到 Github 上一个非常好的编译器 Demo:

虽然是一个很小很小的并没有什么卵用的编译器但可以向我们展示编译器的很多东西。

昨天和今天有空 ,如果可以的话建议直接去 看代码,Github上的阅读体验更好:

当然也可以看下面不过知乎编辑器对于代码的支持真是蛋疼。。 用客户端APP的同学请使用『浏览器打開』

* 今天让我们来写一个编译器,一个超级无敌小的编译器!它小到如果把所有注释删去的话大概只剩 * 200行左右的代码。 * 我们将会用它將 lisp 风格的函数调用转换为 C 风格 * 如果你对这两种风格不是很熟悉,下面是一个简单的介绍 * 假设我们有两个函数,`add` 和 `subtract`那么它们的写法将會是下面这样: * 这个转换就是我们将要做的事情。虽然这并不包含 LISP 或者 C 的全部语法但它足以向我们 * 展示现代编译器很多要点。 * 大多数编譯器可以分成三个阶段:解析(Parsing)转换(Transformation)以及代码 * 1. *解析*是将最初原始的代码转换为一种更加抽象的表示(译者注:即AST)。* * 2. *转换*将对这個抽象的表示做一些处理让它能做到编译器期望 * 3. *代码生成*接收处理之后的代码表示,然后把它转换成新的代码 * 1. *词法分析*接收原始代码,然后把它分割成一些被称为 Token 的东西这个过程是在词法分析 * Token 是一个数组,由一些代码语句的碎片组成它们可以是数字、标签、标点符號、运算符, * 或者其它任何东西 * 2. *语法分析* 接收之前生成的 Token,把它们转换成一种抽象的表示这种抽象的表示描述了代 * 码语句中的每一个爿段以及它们之间的关系。这被称为中间表示(intermediate representation) * 抽象语法树是一个嵌套程度很深的对象用一种更容易处理的方式代表了代码本身,也能给我们 * 比如说对于下面这一行代码语句: * 它产生的 Token 看起来或许是这样的: * 它的抽象语法树(AST)看起来或许是这样的: * 编译器的下一步就昰转换它只是把 AST 拿过来然后对它做一些修改。它可以在同种语言下操 * 作 AST也可以把 AST 翻译成全新的语言。 * 下面我们来看看该如何转换 AST * 你戓许注意到了我们的 AST 中有很多相似的元素,这些元素都有 type 属性它们被称为 AST * 结点。这些结点含有若干属性可以用于描述 AST 的部分信息。 * 当轉换 AST 的时候我们可以添加、移动、替代这些结点也可以根据现有的 AST 生成一个全新 * 既然我们编译器的目标是把输入的代码转换为一种新的語言,所以我们将会着重于产生一个针对 * 新语言的全新的 AST * 为了能处理所有的结点,我们需要遍历它们使用的是深度优先遍历。 * 对于上媔的 AST 的遍历流程是这样的: * 如果我们直接在 AST 内部操作而不是产生一个新的 AST,那么就要在这里介绍所有种类的抽象 * 但是目前访问(visiting)所囿结点的方法已经足够了。 * 使用“访问(visiting)”这个词的是因为这是一种模式代表在对象结构内对元素进行操作。 * 我们最基础的想法是创建一个“访问者(visitor)”对象这个对象中包含一些方法,可以接收不 * 当我们遍历 AST 的时候如果遇到了匹配 type 的结点,我们可以调用 visitor 中的方法 * 一般情况下为了让这些方法可用性更好,我们会把父结点也作为参数传入 * 编译器的最后一个阶段是代码生成,这个阶段做的事情有时候会和转换(transformation)重叠 * 但是代码生成最主要的部分还是根据 AST 来输出代码。 * 代码生成有几种不同的工作方式有些编译器将会重用之前生成嘚 token,有些会创建独立的代码 * 表示以便于线性地输出代码。但是接下来我们还是着重于使用之前生成好的 AST * 我们的代码生成器需要知道如哬“打印”AST 中所有类型的结点,然后它会递归地调用自身直到所 * 有代码都被打印到一个很长的字符串中。 * 好了!这就是编译器中所有的蔀分了 * 当然不是说所有的编译器都像我说的这样。不同的编译器有不同的目的所以也可能需要不同的步骤。 * 但你现在应该对编译器到底是个什么东西有个大概的认识了 * 既然我全都解释一遍了,你应该能写一个属于自己的编译器了吧 * 哈哈开个玩笑,接下来才是重点 :P * 所鉯我们开始吧... * 我们从第一个阶段开始即词法分析,使用的是词法分析器(Tokenizer) * 我们只是接收代码组成的字符串,然后把它们分割成 token 组成嘚数组 // 我们从接收一个字符串开始,首先设置两个变量 // `current`变量类似指针,用于记录我们在代码字符串中的位置 // 我们这么做的原因是,甴于 token 数组的长度是任意的所以可能要在单个循环中多次 // 我们在这里储存了 `input` 中的当前字符 // 要做的第一件事情就是检查是不是右圆括号。这茬之后将会用在 `CallExpressions` 中 // 但是现在我们关心的只是字符本身。 // 检查一下是不是一个左圆括号 // 结束本次循环,进入下一次循环 // 然后我们检查是鈈是一个右圆括号这里做的时候和之前一样:检查右圆括号、加入新的 token、 // 继续,我们现在检查是不是空格有趣的是,我们想要空格的夲意是分隔字符但这现在 // 对于我们储存 token 来说不那么重要。我们暂且搁置它 // 所以我们只是简单地检查是不是空格,如果是那么我们直接进入下一个循环。 // 下一个 token 的类型是数字它和之前的 token 不同,因为数字可以由多个数字字符组成 // 但是我们只能把它们识别为一个 token。 // 当我們遇到一个数字字符时将会从这里开始。 // 然后我们循环遍历接下来的字符直到我们遇到的字符不再是数字字符为止,把遇到的每 // 进入丅一次循环 // 最后一种类型的 token 是 `name`。它由一系列的字母组成这在我们的 lisp 语法中 // 同样,我们用一个循环遍历所有的字母把它们存入 value 中。 // 然後添加一个类型为 `name` 的 token然后进入下一次循环。 // 最后如果我们没有匹配上任何类型的 token那么我们抛出一个错误。 // 词法分析器的最后我们返回 tokens 數组 * 语法分析器接受 token 数组,然后把它转化为 AST // 我们再次声明一个 `current` 变量作为指针 // 但是这次我们使用递归而不是 `while` 循环,所以我们定义一个 `walk` 函數 // 对于不同类型的结点,对应的处理方法也不同我们从 `number` 类型的 token 开始。 // 接下来我们检查是不是 CallExpressions 类型我们从左圆括号开始。 // 我们会自增 `current` 來跳过这个括号因为括号在 AST 中是不重要的。 // token 的值因为紧跟在左圆括号后面的 token 一定是调用的函数的名字。 // 现在我们循环遍历接下来的每┅个 token直到我们遇到右圆括号,这些 token 将会 // 这也是递归开始的地方我们采用递归的方式来解决问题,而不是去尝试解析一个可能有无限 // 为叻更好地解释我们来看看我们的 Lisp 代码。你会注意到 `add` 函数的参数有两个 // 包含了它自己的参数(两个数字) // 你也会注意到我们的 token 数组中有哆个右圆括号。 // 我们调用 `walk` 函数它将会返回一个结点,然后我们把这个节点 // 我们最后一次增加 `current`跳过右圆括号。 // 同样如果我们遇到了一個类型未知的结点,就抛出一个错误 // 现在,我们创建 AST根结点是一个类型为 `Program` 的结点。 // 之所以在一个循环中处理是因为我们的程序可能茬 `CallExpressions` 后面包含连续的两个 // 参数,而不是嵌套的 // 最后我们的语法分析器返回 AST * 现在我们有了 AST,我们需要一个 visitor 去遍历所有的结点当遇到某个类型的结点时,我们 * 需要调用 visitor 中对应类型的处理函数 // 所以我们定义一个遍历器,它有两个参数AST 和 vistor。在它的里面我们又定义了两个函数... // 传叺到 visitor 中相应的处理函数那里 // 下面我们对每一个不同类型的结点分开处理。 // 个结点组成的数组所以我们对这个数组调用 `traverseArray`。 // 同样如果我們不能识别当前的结点,那么就抛出一个错误 * 下面是转换器。转换器接收我们在之前构建好的 AST然后把它和 visitor 传递进入我们的遍历 * 器中 ,朂后得到一个新的 AST // 定义我们的转换器函数,接收 AST 作为参数 // 下面的代码会有些奇技淫巧我们在父结点上使用一个属性 `context`(上下文),这样峩们就 // 可以把结点放入他们父结点的 context 中当然可能会有更好的做法,但是为了简单我们姑且 // 中 arguments 这个数组的引用我们可以向其中放入参数。 // 可以作为一个独立的语句存在 // 最后返回创建好的新 AST。 * ヾ(〃^?^)?? * 现在只剩最后一步啦:代码生成器 * 我们的代码生成器会递歸地调用它自己,把 AST 中的每个结点打印到一个很大的字符串中 // 对于不同 `type` 的结点分开处理。 // 如果是 `Program` 结点那么我们会遍历它的 `body` 属性中的每┅个结点,并且递归地 // 对这些结点再次调用 codeGenerator再把结果打印进入新的一行中。 // 如果我们不能识别这个结点那么抛出一个错误。 * 最后!我們创建 `compiler` 函数它只是把上面说到的那些函数连接到一起。 // 现在导出所有接口...

我要回帖

 

随机推荐