从零开始写个编译器吧 - Parser 语法分析器

Parser(语法分析器)的编写相对于 Tokenizer (词法分析器)要复杂得多,因此,在编写之前可能也会铺垫得更多一些。当然,本系列旨在“写出”一个编译器,所以理论方面只会简单介绍 tao 语言所涉及的部分。
之前的几章中,我纯手写了tao 语言的 Tokenizer。但如果我准备也纯手写一个 Parser,那将是非常麻烦且繁琐的一件事情。实际上,就在在写出这篇文章之前,我已完成了 Parser 的编写,并测试妥当,因此我可以在此面对各位得出这个结论。

我将使用这么一种方式“制造”出 Parser:

  1. 将 tao 语言的所有语法细节描述出来,即定义 tao 语言。
  2. 写一个能”根据定义,生成 tao 语言的 Parser“的程序。

如果以上描述有些让人困惑,那我举个通俗点的例子吧:

假如我想要制作一双鞋子,通常的方案是,我会买好材料,并把鞋子做出来。但还有另一种方案,我先画出鞋子的设计图,再造一台能依照设计图造出鞋子的机器,然后把设计图交给机器,再发动机器,得到鞋子

在”制造鞋子的世界“中,除非我要开鞋厂,否则若我仅仅想造双鞋子,那么前一个方案显然更好。但在”制造编译器的世界“中,却与直觉相反,当语言本身足够复杂的时候,后一种方案比前一种方案要方便得多。

至此,我需要一个能读懂 tao 语言的定义,并根据定义生成 Parser 的一个程序。这种程序我们称之为 Compiler-compiler 。这样的程序(或称工具)有很多现成的可供选择(包括在 Java 平台上可用的),但既然我这个系列叫做《从零开始写个编译器吧》,那显然如果我用现成的工具,那是犯规行为。

  • 因此,我还要写一个 Compiler-compiler 出来才行。

那么,让我先贴一张图,以描述我将会写出的 Compiler-compiler 的工作原理吧。

4169a92a3c42060aa326d13892175708_b.jpg

Compiler-compiler 会将 tao 语言的定义编译成某种数据结构,而这种数据结构是 Parser 初始化的参数。Parser 只有获得了这种数据结构才能正常工作。

当 Parser 初始化之后,它会读取 Tokenizer 生成的 Token 序列,并同时通过解释 Compiler-compiler 生成的数据结构,最后生成 Syntax Tree。

至此,在编写 Parser 的章节中,我必须完成如下三个任务。

  1. 定义 tao 语言的语法细节,并挑选一个合适的形式描述出来。
  2. 编写一个 Compiler-compiler,它能编译 tao 语言的定义,并生成某种数据结构。
  3. 编写一个 Parser,它通过解释 Compiler-compiler 生成的数据结构,将 Token 序列编译成 Syntax Tree。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java精神(基于函数式组合子逻辑的javaparser框架) 一。 释名。 为什么叫精神? 如果你熟悉c++,那么你可能知道一个叫做”spirit”的parser库。它利用c++的模板元编程能力,使用c++语言本身提供了一个递归下降文法解析的框架。 我这里介绍的jparsec库,就是一个java里面的递归下降文法解析框架。 不过,它并非是spirit的java版本。 Jparsec的蓝本来自Haskell语言的parsec库。Parsec是一个基于monad的parser组合子库。 这个库的目的是要在java中提供一个类似parsec, spirit的库,这种组合子库并非c++的专利,java/c#也可以做到。这个库还将在java5.0上被改写,类型安全上它将也不再逊色于c++。 那么,为什么叫“函数式”呢?java是面向对象的嘛。 如果你使用过haskell, lisp等语言,这个函数式不用解释你也知道是怎么回事了。 如果你是一个老牌的c++/java程序员,那么这里还要稍微解释一下。当然如果您对这些虚头八脑的名词不感兴趣,那么,你尽可以跳过这一章,不知道什么是“函数式”,并不会影响你对这个库的理解的。 C++这几年随着gp的普及,“函数式”这个老孔乙己逐渐又被人从角落里面拽了出来。一个c++程序员所熟悉的“函数式”很可能是stl的for_each, transform,count_if这些函数。 怎么说呢,就象我不能否定str.length()这个调用属于OO一样,我也无法说for_each, transform不是函数式。 但是,“函数式”的精髓不在于此。 一般归纳起来,就像我们说OO是什么多态,封装,继承一样,“函数式”的特征被总结为: 1。无副作用。 2。高阶函数。 3。延迟计算 而最最有意义的(至少我认为如此),是基于高阶函数的函数组合能力。一些人把这叫做glue。 简短地说,什么让函数式编程如此强大?是用简单的函数组合出复杂函数的能力。 我可以想象,说到这里,你还是一头雾水。“什么是组合?1+1不是也把两个1组合成2了吗?new A(new B(), new C())不也是从B和C组合成A了?”
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值