// 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 = [...]
Tag Archives: syntax
自己动手开发编译器(十):miniSharp语法分析器
经过前面四篇的铺垫,我们终于拥有了编写语法分析器的强大工具,现在可以正式开发一门编程语言的语法分析器了。我们先来定义 miniSharp 的语法规则,然后根据 LL 文法的特点进行一些调整,最后借助解析器组合子生成完整的语法分析器。
自己动手开发编译器(九)CPS风格的解析器组合子
上回我们用函数式编程的方法,结合 Linq 语法,建立了一套解析器组合子方案,并能成功解析自定义文法的输入字符串。但是,上次做成的解析器组合子有个重要的功能没有完成——错误报告。作为编程语言的语法分析器,不能在遇到语法错误的时候简单地返回 null ,那样程序员就很难修复代码中的语法错误。我们需要的是准确报告语法错误的位置,更进一步,是程序中所有的语法错误,而不仅仅是头一个。后者要求解析器具有错误恢复的能力,即在遇到语法错误之后,还能恢复到正常状态继续解析。错误恢复不仅仅可以用在检测出所有的语法错误,还可以在存在语法错误的时候仍然提供有意义的解析结果,从而用于 IDE 的智能感知和重构等功能。手写的递归下降语法分析器可以很容易地加入错误恢复,但需要针对每一处错误手工编写代码来恢复。像 C#官方编译器,给出的语法错误信息非常全面、精确、智能,全都是手工编写的功劳。又回到我们是懒人这个残酷的事实,能不能在让解析器组合子生成的解析器自动具有错误恢复能力呢?
自己动手开发编译器(八)用Linq编写解析器组合子
上回我们说到手写递归下降语法分析器。手写递归下降的方式是目前很多编译器采用的方式,如果你想写一个商业质量的编译器,这是首选的方法。但是,一个完善的递归下降解析器需要的代码量也不少,如果要进行错误报告、错误恢复等等那代码量就更大了。作为懒人,我们有时想要一些小型语言的解析器,最好写起来像直接写文法的产生式一样,最好连错误报告和错误恢复也一并自动解决,可能吗?在过去很长一段时间,人们采用的方法是使用解析器生成器(parser generator)。因为不管是 LL 递归下降解析还是 LR 的移进归约解析,都可以很容易地用计算机来生成所需的规则。这样的著名工具有 yacc、 ANTLR 等。他们的特点是要用一种专门的语法格式来编写文法产生式,然后经过一个翻译程序生成解析器的代码。在函数式语言发展起来之后,有些人发现函数式语言的抽象能力非常强,甚至能够直接用函数式语言的代码来表达文法的产生式,并将解析器“组合”出来,这称作解析器组合子(parser combinator)。如今 C# 和 VB 语言也具有函数式语言相当的特征,特别是还有 Linq 助阵,以至于在 C# 和 VB 中也能享受组合子带来的方式。今天我们就来看看怎么做解析器的组合子。这一篇文字描述可能比较模糊,大家一定要认真地看代码,动手实验。
自己动手开发编译器(七)递归下降的语法分析器
上回我们说到语法分析使用的上下文无关语言,以及描述上下文无关文法的产生式、产生式推导和语法分析树等概念。今天我们就来讨论实际编写语法分析器的方法。今天介绍的这种方法叫做递归下降(recursive descent)法,这是一种适合手写语法编译器的方法,且非常简单。递归下降法对语言所用的文法有一些限制,但递归下降是现阶段主流的语法分析方法,因为它可以由开发人员高度控制,在提供错误信息方面也很有优势。就连微软C#官方的编译器也是手写而成的递归下降语法分析器。
自己动手开发编译器(六)上下文无关语言和文法
上回我们已经学习了语法分析第一阶段——词法分析的原理和工具,介绍了正则表达式、正则语言和DFA等工具。今次我们要开始涉及编译器前端最重要的阶段——语法分析。简单而言,这一步就要完整地分析整个编程语言的语法结构。上回说到词法分析的结果是将输入的字符串分解成一个个的单词流,也就是诸如关键字、标识符这样有特定意义的单词。一种完整的编程语言,必须在此基础上定义出各种声明、语句和表达式的语法规则。观察我们所熟悉的编程语言,其语法大都有某种递归的性质。例如四则运算与括号的表达式,其每个运算符的两边,都可以是任意的表达式。比如1+a是表达式,(1+a)*(2 – c)也是表达式,((a+b) + c) * (d – e)也是表达式。再比如if语句,其if的块和else的块中还可以再嵌套if语句。我们在词法分析中引入的正则表达式和正则语言无法描述这种结构,如果用DFA来解释,DFA只有有限个状态,它没有办法追溯这种无限递归。所以,编程语言的表达式,并不是正则语言。我们要引入一种表现能力更强的语言——上下文无关语言。
一个“大”题目有趣的答案
lifesinger 出了个题目: f = function() { return true; }; g = function() { return false; }; ( function() { if (g() && [] == ![]) { f = function f() { return false; }; function g() { return true; }; } })(); f(); // What’s the result?