Eisa 近况

巨坑地址:http://github.com/infinte/eisa

  • 把「两个」代码生成器合并了不少,主要是表达式的部分。原来 LFC 里,非阻塞的函数和连续体的代码生成器是分开的,然而很多段代码都大同小异(就是 transform 和 expPart 的区别,这两个函数都是进行递归变换的函数,不过行为不同),现在合并了。
  • 现在的 LFC 里,全局变量必须手工指定,以后会简化设置它的方法,比如允许 JavaScript 全局变量直接绑定到 lofn 的顶层函数里
  • 文档这个巨坑慢慢填罢

顺便贴个东西:用源码的面积计算 pi 复刻版:

var c = 0; var l = 0
def x(n) = (c += (2 if (n == x), 1)) then (l = n if(l < n), l) then (n + 1)
def x.valueOf = {1}
              x x x x x
         x x x x x x x x x x
      x x x x x x x x x x x x x
   x x x x x x x x x x x x x x x x
  x x x x x x x x x x x x x x x x x
  x x x x x x x x x x x x x x x x x
 x x x x x x x x x x x x x x x x x x
 x x x x x x x x x x x x x x x x x x
 x x x x x x x x x x x x x x x x x x
 x x x x x x x x x x x x x x x x x x
  x x x x x x x x x x x x x x x x x
  x x x x x x x x x x x x x x x x x
   x x x x x x x x x x x x x x x x
      x x x x x x x x x x x x x
          x x x x x x x x x
              x x x x x
4 * c / l / l // result

Edit: 果然我很习惯改语法…… ~~ 改成 then

Posted in Original, 中文 | Leave a comment

0x5f3759df 是怎么算出来的?

(注:本文包含数学公式,使用 SVG 图形格式,请不要在 RSS 阅读器里阅读本文)

基本上每个程序员都会对 Quake 那个神一样的常量 0x5f3759df 感到惊奇。在 Quake 里,有一段代码是计算光照时候使用的函数,计算 ,那段代码写的真叫经典:

float Q_rsqrt( float number ){
  long i;
  float x2, y;
  const float threehalfs = 1.5F;

  x2 = number * 0.5F;
  y  = number;
  i  = * ( long * ) &y;  // evil floating point bit level hacking
  i  = 0x5f3759df - ( i >> 1 ); // WTF?
  y  = * ( float * ) &i;
  y  = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
  // y  = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed

  return y
}

任何学过数值分析的人肯定都知道,最后两行干的事情是牛顿迭代法,用迭代逼近算出准确值。整个过程里,先把单精度浮点 number “硬”转换成整数,进行一个非常诡异的减法后捣腾回实数,然后进行牛顿迭代。那个诡异的步骤显然是算出 的一个近似值,而且从只迭代了一次看,猜测的非常好。因为是计算光照用,千分之一的误差是可以允许的,否则,多迭代几行就是。

这肯定会引来无数人遐想的。不过你看过下面一段内容后就知道其中就里了。

根据 IEEE-754,每一个正的二进制浮点数都可以表示成 。其中, 为其小数位,而 是其指数部分。对于单精度来说, 有 23 个二进制位,而 则有 8 位,

我们把它转换成“无符号整数形式” 。对比两者可以得到:

那好,为了计算 ,两边取对数,有:

为了去掉那个该死的对数,考虑到 在[0, 1] 上, ,在这里引入一个常数 σ 使得 。于是:

这样就可以解释那一行里那个著名的 0x5f3759df 实际上就是 。取 σ = 0 代入尝试,可得到 R = 1598029824 = 0x5f400000。这个数值已经比较接近了,然而还不准确,毕竟这里 σ = 0。

那么 σ 设置成多少合适呢?由于希望用牛顿法计算,自然需要让 差异尽量小。我使用的是最小二乘法,即计算积分:

积分 的结果是 σ 的二次函数,可算出其最小值时,σ 为 。利用这个 σ 计算出的 R = 0x5f34ff58。Quake 里使用的 σ = 0.0450461875791687011756,比用最小二乘法算出的 σ 小。另一个可以选用的 σ 是 在 [0, 1] 上的最大值的一半,为 ,算出的 R 为 1597488340 = 0x4f37bcb6

当然了,用最小二乘法去“猜” σ 并不是非常好,最好的 σ 肯定是用大量实验选择的, 这个 σ 值并不是非常好的值,但是作为一次尝试,已经是很不错了。

Posted in Depth, Discussion, 中文 | Tagged , , | 2 Comments

你喜欢这样定义类吗?这就是 eisa 的 def

// Also: Man = type(function(name)...)
def type Man(name = "Unnamed"):
    @name = name
end
def Man.prototype.say(something):
    tracel @name + ': ' + something
end
var tom = Man.new 'Tom';
tom.say 'Hello'
// Also: Priate = outof(Man)(function(name, spname)...)
def outof(Man) Priate(name = "Unnamed", spname = "Unknown"):
    Man.call this, name
    @spname = spname
end
var beard = Priate.new 'Peter', 'Blue Beard'
tracel beard.spname
beard.say 'Yarr!'
Posted in Discussion, Original, 中文 | Tagged , , , | 3 Comments

行数 17259

http://gist.github.com/1277224

从 8 行到 17259 行。从一个侧面也证明了把静态语言“编译”成动态语言有多困难。Dart 注定是个笑话。

ps. 今天 Eisa 的总行数只有 4643 行。

Posted in Browser, Critique, 中文 | Tagged , , | 1 Comment

自己动手开发编译器(补完)

第十一:http://www.cnblogs.com/Ninputer/archive/2011/07/22/2112030.html

第十二:http://www.cnblogs.com/Ninputer/archive/2011/08/02/2120435.html

没想到作者自己坑掉了 0_0
那我也跟着坑掉好了(本来还想看看后端技术地说)

Posted in Discussion, dotNET/mono, 中文 | Tagged | Leave a comment

自己动手开发编译器(十):miniSharp语法分析器

经过前面四篇的铺垫,我们终于拥有了编写语法分析器的强大工具,现在可以正式开发一门编程语言的语法分析器了。我们先来定义 miniSharp 的语法规则,然后根据 LL 文法的特点进行一些调整,最后借助解析器组合子生成完整的语法分析器。

Read More »
Posted in Depth, dotNET/mono, 中文 | Tagged , , , , | 1 Comment

自己动手开发编译器(九)CPS风格的解析器组合子

上回我们用函数式编程的方法,结合 Linq 语法,建立了一套解析器组合子方案,并能成功解析自定义文法的输入字符串。但是,上次做成的解析器组合子有个重要的功能没有完成——错误报告。作为编程语言的语法分析器,不能在遇到语法错误的时候简单地返回 null ,那样程序员就很难修复代码中的语法错误。我们需要的是准确报告语法错误的位置,更进一步,是程序中所有的语法错误,而不仅仅是头一个。后者要求解析器具有错误恢复的能力,即在遇到语法错误之后,还能恢复到正常状态继续解析。错误恢复不仅仅可以用在检测出所有的语法错误,还可以在存在语法错误的时候仍然提供有意义的解析结果,从而用于 IDE 的智能感知和重构等功能。手写的递归下降语法分析器可以很容易地加入错误恢复,但需要针对每一处错误手工编写代码来恢复。像 C#官方编译器,给出的语法错误信息非常全面、精确、智能,全都是手工编写的功劳。又回到我们是懒人这个残酷的事实,能不能在让解析器组合子生成的解析器自动具有错误恢复能力呢?

Read More »
Posted in Depth, dotNET/mono, 中文 | Tagged , , , , | Leave a comment

JavaScript: 死或新生

原作:JavaScript is Dead. Long Live JavaScript!

翻译: Belleve Invis

此翻译非直译,可能有部分内容省略,为交流用。如有错漏请回复。

十六年来, JavaScript 已经完全占领浏览器。它,见证了网页应用(Web Application)的崛起。尽管其他的脚本语言也能担此重任,然而,命运选择了 JavaScript。尽管微软在数年前就在浏览器里加入了 Basic ,但, JavaScript 因为能在所有浏览器中运行,所以它赢了。因能在所有浏览器中运行,自身的质量又并不差,那些浏览器制造商就没有义务给他们的产品增加新语言。

那些华丽的特性——比如闭包——让她成为我们这些情人眼里的西施。编程圈子里经常有这样的忏悔——“是,我知道,这玩意不怎么样,但是给她个机会,好吗?你会爱上她的。”给这语言推销绝非难事。 JavaScript 被说成一个太早拿出来的实验品,而我们一直戴着有色眼镜。

2007 年, Steve Yegge 说 JavaScript 会“引爆程序圈”,现在看来,是真的。从那时到现在,基于 JavaScript 的网页应用已经变得更复杂、更大型以及更好用。借其力量, Web 仍然保持繁荣,丝毫不让移动 App。

最近, JavaScript 在服务器端成功发力。 Node.js 平台,利用其非阻塞 I/O,有望解决无数程序员多年的积怨。作为 Node.js 的选择, JavaScript 可能会在服务器端完成无数前人没有完成的任务。

总而言之, JavaScript 早已横扫全球。但是,如果浏览器今天从地球上消失,又有多少 JavaScript 代码会在第二天写出来?或许她会一夜之间被打入冷宫。幸而,浏览器不会消失,而且还会存活很多年。

随着开发规模的膨胀,那些缺陷逐渐显现,日复一日戳痛开发人员的心。你会觉得奇怪,为什么我写 JavaScript 那么多年我还不是 JavaScript 教教徒,我写的绝大多数 JavaScript 文章都在说我怎么克服重重障碍与之和谐相处的。我很喜欢 JavaScript 编程,但也很多次感觉犹如陷入泥潭。

一个最明显的缺陷——能直接看到的——就是语法。这问题不解决,它迟早要倒台。

Posted in Browser, Discussion, Translation, 中文 | Tagged , , | 4 Comments

自己动手开发编译器(八)用Linq编写解析器组合子

上回我们说到手写递归下降语法分析器。手写递归下降的方式是目前很多编译器采用的方式,如果你想写一个商业质量的编译器,这是首选的方法。但是,一个完善的递归下降解析器需要的代码量也不少,如果要进行错误报告、错误恢复等等那代码量就更大了。作为懒人,我们有时想要一些小型语言的解析器,最好写起来像直接写文法的产生式一样,最好连错误报告和错误恢复也一并自动解决,可能吗?在过去很长一段时间,人们采用的方法是使用解析器生成器(parser generator)。因为不管是 LL 递归下降解析还是 LR 的移进归约解析,都可以很容易地用计算机来生成所需的规则。这样的著名工具有 yacc、 ANTLR 等。他们的特点是要用一种专门的语法格式来编写文法产生式,然后经过一个翻译程序生成解析器的代码。在函数式语言发展起来之后,有些人发现函数式语言的抽象能力非常强,甚至能够直接用函数式语言的代码来表达文法的产生式,并将解析器“组合”出来,这称作解析器组合子(parser combinator)。如今 C# 和 VB 语言也具有函数式语言相当的特征,特别是还有 Linq 助阵,以至于在 C# 和 VB 中也能享受组合子带来的方式。今天我们就来看看怎么做解析器的组合子。这一篇文字描述可能比较模糊,大家一定要认真地看代码,动手实验。

Read More »
Posted in Depth, dotNET/mono, 中文 | Tagged , , , , | Leave a comment

自己动手开发编译器(七)递归下降的语法分析器

上回我们说到语法分析使用的上下文无关语言,以及描述上下文无关文法的产生式、产生式推导和语法分析树等概念。今天我们就来讨论实际编写语法分析器的方法。今天介绍的这种方法叫做递归下降(recursive descent)法,这是一种适合手写语法编译器的方法,且非常简单。递归下降法对语言所用的文法有一些限制,但递归下降是现阶段主流的语法分析方法,因为它可以由开发人员高度控制,在提供错误信息方面也很有优势。就连微软C#官方的编译器也是手写而成的递归下降语法分析器。

Read More »
Posted in Depth, dotNET/mono, 中文 | Tagged , , , | Leave a comment