笔记-编程语言实现模式(Language Implementation Patterns)

第1章 语言应用初探 Lanugage Applications Cracked Open

1.1 大局观 The Big Picture

主要思想:文件读取部分对输入内容进行“识别”,并输出数据结构作为中间表示(intermediate representation,IR),供其他部件使用。流水线的末端是生成器,会根据IR及之前所收集到的信息进行计算,并输出最终所需的结果。那么这之间的过程就是进行语义分析。

图形地址:ProcessOn Flowchart

1.2 模式概览 A Tour of the Patterns

  • 解析输入语句:解析输入内容的结构

    • 2、3章文件读取器所涉及的模式

    • 还会对文法进行一些讲解(用形式语言描述的),跟解释器识别语言的原理有关

      • 第一种模式根据文法手工编写解析器:ANTLR(或类似的解析器、生成器 www.antlr.org)可以自动实现这个功能

      • 简单的输入组件,模式二和模式三可以识别输入语句

      • 模式四:增加每次读入字符的个数,解析器的解析能力会得到提高

      • 模式五:更复杂情况,解析器得读入整个语句才能解析

      • 模式六:回溯法,解析能力强大,但运行效率较低

      • 模式七:最强大的解析能力,谓词解析器能根据运行时的信息进行动态调整,切换到正确的解析流上

  • 构建语法树:为避免重新解析输入流,可以生成一些数据结构作为IR

    • 模式八:第一个有关树的模式。解析树中含很多无用信息。如果要编写源代码分析器或者翻译器等应用,通常会采用抽象语法树(abstract syntax tree, AST),主要考虑遍历树的方式(前中后序等等)

    • 模式九:所有节点都用同种类型表示

    • 模式十:多类型节点

    • 模式十一:异型节点

  • 遍历树:树的遍历方法选择

    • 模式十二:把方法内置于每个节点的类中

    • 模式十三:把方法封装在外部访问者里

    • 模式十四、十五:使用工具自动生成访问者,就像自动生成解析器一样

  • 弄清输入的含义:要想生成有用的输出结果,就必须分析输入内容,以获取相关的信息(语义分析),符号表。符号表所采用的的模式取决于语言的语义规则。

    • 模式十六:单一作用域规则

    • 模式十七:嵌套作用域规则

    • 模式十八:C结构体作用域规则

    • 模式十九:类作用域规则

    • 模式二十、二十一:为类C/C++语言打好基础

    • 模式二十二:类C语言非面向对象语言处理

    • 模式二十三:类C++语言面向对象语言处理

  • 解释输入语句:解释器能运行IR中的指令,但一般也要使用符号表之类的数据结构

    • 模式二十四、二十五、二十七、二十八:从作用上来说等价,常见的解释器模式,只是在指令集、运行效率、交互性、易用性及实现的难度上存在差异

  • 翻译语言:任何翻译器的末端都是生成器,能产生结构化的文本或者二进制数据

    • 模式二十九:模型驱动领域方法、模版引擎(逆解析器等,如书中的StringTemplate www.stringtemplate.org

1.3 深入浅出语言应用 Dissecting a Few Applications

字节码解释器

用软件模拟出硬件处理器,因此也被称作虚拟机。指令集比较底层,但是没有机器代码那么底层。指令集里的指令往往用一个字节(能表示0到255之间不同的整数)就能表示,因此又称为字节码。

包括Java、Lua、Python、Ruby、C#和Smalltalk在内的语言都采用字节码解释器来实现。Lua实现方式采用模式二十八,其他几个用的是模式二十七。在1.9版本以前,Ruby实现方式类似于模式二十五。

Java差错程序1

本例的语义分析中,需要遍历IR两次,第一次记录所有的符号(标识符),第二次找出所有等号两边一样的赋值语句。

大部分文件的读取都分为两个阶段,首先把输入的字符流分成基本符号,即词法单元,之后用语法解析器检查词法单元的语法。在这个例子里,词法分析器(有些书中也称lexer)会输出如下符号流: ... void setX ( int y ) { ...

语法解析器一边进行语法扫描,一边构建IR。

Java差错程序2

Java编译器输出.class文件,里面是序列化的符号表和AST。使用字节码工程库(byte code engineering library,BCEL)或类似的class文件读取器,就可以直接载入.class文件并分析,而不用自己编写源代码读取器了(实际上,FindBugs就用了这种方式)。图1.5所示的是这种方法的流水线图。(略)

javac也是编译器,其基本原理与传统的C语言编译器的一样。唯一的区别就是C编译器最终会把代码翻译为某个特定平台上的指令。

C编译器

预处理=>加行号的C代码=>编译器处理=>输出汇编代码(机器码的文本助记符)=>汇编器生成最终的二进制机器码

gcc 命令后加上参数-S,就可以把tmp.c编译成汇编代码(tmp.s),而不直接生成机器码。再使用as命令,就可以得到目标文件tmp.o: as -o tmp.o tmp.s(#把tmp.s汇编为tmp.o)

C编译器的流水线:

编译器最复杂的地方是语义分析和优化。

借助C编译器实现C++语言

Bjarne Stroustrup使用了已有的C编译器来完成对C++的编译。

具体来说,他只编写了翻译器(cfront),能把C++翻译成C,而没有编写真正的C++编译器。

由文件读取器、语义解析器和生成器组成。

1.4 为语言应用选择合适的模式 Choosing Patterns and Assembling Applications

程序员常做的两件事:一是实现某个DSL,二是处理或者翻译GPPL(General-Purpose Programming Language,是指类似C、Java等功能较为完备的编程语言)。换言之,程序员可能得实现某种制图语言或者数学语言,但很少需要编写大型程序语言的编译器或解释器。通常所遇到的任务不外乎是编写一些重构、格式调整、度量软件、错误查找、插桩或者翻译语言的工具。

编译器用到的模式,往往也是实现DSL甚至GPPL所需要的关键模式。比如符号表管理模式,几乎所有语言应用都以之为基础。

语言应用中,最基本的架构就是将词法分析模式和语法分析模式组合起来,这是模式二十四和二十九的核心。

另一个基本架构会对输入进行分析并构建AST(通过解析器来构造树),而不会对其进行实时处理。构建好AST之后,就可以对输入的内容进行多次遍历,而不用重复解析,这是比较高效的作法。比如模式二十五的while每次都会重新访问AST节点。

第2章 基本解析模式 Basic Parsing Patterns

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江湖大老弟

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值