My Blogs

Posts tagged with "编译器"

通过实例看解释器和编译器的区别

Tags: JavaScript , 编译器 , 解释器 , 程序设计语言理论

Published 2015年04月25日 23:00 by james

本文将通过一个简单例子来对比一下解释器和编译器的区别。

在实现Compiler(编译器)和Interpreter(解释器)之前,我们需要先选择一种目标语言,这里我们选用计算器语言,它的文法非常简单,而且可以很方便地扩展,除了四则运算之外,如果有需要,我们可以很方便地加入负数,平方,开方,幂,括号及变量等。

本例,为了演示简单,我们的计算器仅支持四则运算,负数和括号。

expression : term | expression '+' term | expression '-' term
term : primary_expression | term '*' primary_expression | term '/' primary_expression
primary_expression : DOUBLE_LITERAL | '(' …

零基础构建语言解释器

Tags: 函数式编程 , 程序设计语言理论 , Lambda , Lisp , JavaScript , 编译器 , 解释器

Published 2015年04月01日 23:00 by james

在编写Interpreter之前,我们需要先了解Lexer(词法分析器),Parser(语法解析器),AST(抽象语法树)。

一般情况下,Interpreter在解释执行程序时,一般会经过如下步骤。

  1. Lexer读入程序代码,把代码转换token序列。
  2. Parser把读到的token序列转换为AST(大部分情况下,Lexer内嵌为Parser的一部分)。
  3. 对AST进行Lowering(化简AST)或者desugar(把语法糖的AST节点转换为标准等价AST节点)处理。
  4. Interpreter递归执行AST,AST决定了代码的执行顺序。

alternative text

介绍完了基本的一些概念,我们现在开始来实现语言解释器。

首先,我们需要先定制文法规则,一般情况下,我们只要制定好了文法规则,就可以找一些工具来帮我们生成AST,对于复杂的文法规则,手写Parser是非常麻烦并且乏味的。 这里,为了简单,我们选用S-Expression来作为我们的文法规则来实现Lambda Calculus(Lambda演算)的解释器。 通过该Interpreter的实现,大家可以很容易就搞明白程序设计语言中耳熟能详却又未必深刻了解的一些概念,比如:类型,Lexical Scope(词法作用域),Dynamic Scope(动态作用域),闭包等概念。

Lambda Calculus

虽然规则简单,Lambda演算却是一门强大的语言。它的三个元素分别是是:变量,函数,调用。用传统的表达法,它们看起来就是:
    变量:x
    函数:λx.t
    调用:t1 t2

每个程序语言里面都有这三个元素,只不过具体的语法不同,所以你其实每天都在使用 lambda calculus。换成S-Expression就是:
    变量:x
    函数:(lambda (x) e)
    调用:(e1 …