编辑推荐
适读人群:主要面对三类人群:1对脚本语言实现原理感兴趣,2对编译原理和虚拟机感兴趣,3对Lua语言感兴趣,想探究其内部实行
(1)作者是的服务器开发工程师和架构师,精通Java、GO和Lua等语言,对高级语言的虚拟机有深入研究,《自己动手写Java虚拟机》作者。
(2)《自己动手实现Lua:虚拟机、编译器和标准库》3大内容特色:零基础自制编程语言、彻底掌握Lua语言实现原理和工作机制、提升Go和Java语言编程能力。
(3)《自己动手实现Lua:虚拟机、编译器和标准库》得到了七牛云创始人兼CEO等大佬的高度评价和推荐。内容简介
《自己动手实现Lua:虚拟机、编译器和标准库》是一本面向Lua程序员和脚本语言爱好者的语言自制指南和实战宝典。作者融合自己丰富的工程实践经验,详细阐述Lua语言的核心语法和实现原理,深入探讨Lua虚拟机、编译器和标准库,并给出了实际可以编译执行的代码。助你从零基础开始编程实现Lua语言,彻底理解脚本语言工作原理。《自己动手实现Lua:虚拟机、编译器和标准库》分为3个部分,共21章。部分主要讨论LuaAPI和虚拟机实现,包括二进制chunk格式、Lua虚拟机指令集、元编程、错误处理等。第二部分主要讨论Lua语法和编译器实现,包括词法分析、语法分析、代码优化、代码生成等。第三部分主要讨论Lua辅助API和标准库实现,包括基础库、实用工具库、包和模块、协程等。作者简介
张秀宏
服务器开发工程师,有多年的Java和游戏服务器开发和架构经验,对高级语言虚拟机有非常深入的研究。曾在EA、乐元素等游戏公司担任高级服务器工程师,现任某创业公司架构师。
曾于2016年6月出版《自己动手写Java虚拟机》一书,广受读者好评,并多次重印。《自己动手实现Lua:虚拟机、编译器、标准库》是他时隔两年之后推出的又一力作。
目录
前言
第一部分 准备
第1章 准备工作3
1.1 准备开发环境3
1.1.1 操作系统3
1.1.2 安装Lua4
1.1.3 安装Go4
1.2 准备目录结构4
1.3 本章小结6
第二部分 Lua虚拟机和LuaAPI
第2章 二进制chunk9
2.1 什么是二进制chunk10
2.2 luac命令介绍11
2.2.1 编译Lua源文件11
2.2.2 查看二进制chunk13
2.3 二进制chunk格式15
2.3.1 数据类型16
2.3.2 总体结构17
2.3.3 头部18
2.3.4 函数原型22
2.4 解析二进制chunk27
2.4.1 读取基本数据类型28
2.4.2 检查头部29
2.4.3 读取函数原型30
2.5 测试本章代码33
2.6 本章小结36
第3章 指令集37
3.1 指令集介绍37
3.2 指令编码格式38
3.2.1 编码模式38
3.2.2 操作码39
3.2.3 操作数40
3.2.4 指令表41
3.3 指令解码42
3.4 测试本章代码44
3.5 本章小结47
第4章 LuaAPI49
4.1 LuaAPI介绍49
4.2 Lua栈51
4.2.1 Lua数据类型和值51
4.2.2 栈索引54
4.2.3 定义luaStack结构体54
4.3 LuaState57
4.3.1 定义LuaState接口57
4.3.2 定义luaState结构体58
4.3.3 基础栈操纵方法59
4.3.4 Push方法64
4.3.5 Access方法65
4.4 测试本章代码69
4.5 本章小结70
第5章 Lua运算符71
5.1 Lua运算符介绍71
5.2 自动类型转换75
5.3 扩展LuaState接口79
5.3.1 Arith()方法80
5.3.2 Compare()方法83
5.3.3 Len()方法85
5.3.4 Concat()方法86
5.4 测试本章代码87
5.5 本章小结88
第6章 虚拟机雏形89
6.1 添加LuaVM接口89
6.1.1 定义LuaVM接口91
6.1.2 改造luaState结构体92
6.1.3 实现LuaVM接口93
6.2 实现Lua虚拟机指令94
6.2.1 移动和跳转指令94
6.2.2 加载指令96
6.2.3 算术运算指令101
6.2.4 长度和拼接指令103
6.2.5 比较指令106
6.2.6 逻辑运算指令107
6.2.7 for循环指令110
6.3 指令分派113
6.4 测试本章代码115
6.5 本章小结118
第7章 表119
7.1 表介绍119
7.2 表内部实现121
7.3 表相关API125
7.3.1 Get方法126
7.3.2 Set方法129
7.4 表相关指令131
7.4.1 NEWTABLE131
7.4.2 GETTABLE133
7.4.3 SETTABLE135
7.4.4 SETLIST136
7.5 测试本章代码138
7.6 本章小结140
第8章 函数调用141
8.1 函数调用介绍141
8.2 函数调用栈143
8.2.1 调用帧实现144
8.2.2 调用栈实现145
8.3 函数调用API147
8.3.1 Load()148
8.3.2 Call()149
8.4 函数调用指令152
8.4.1 CLOSURE152
8.4.2 CALL153
8.4.3 RETURN157
8.4.4 VARARG158
8.4.5 TAILCALL159
8.4.6 SELF160
8.4.7 扩展LuaVM接口162
8.4.8 改进SETLIST指令163
8.5 测试本章代码164
8.6 本章小结166
第9章 Go函数调用167
9.1 Go函数登场167
9.1.1 添加Go函数类型168
9.1.2 扩展LuaAPI169
9.1.3 调用Go函数170
9.2 Lua注册表172
9.2.1 添加注册表172
9.2.2 操作注册表173
9.3 全局环境175
9.3.1 使用API操作全局环境175
9.3.2 在Lua里访问全局环境178
9.4 测试本章代码179
9.5 本章小结181
第10章 闭包和Upvalue183
10.1 闭包和Upvalue介绍183
10.1.1 背景知识183
10.1.2 Upvalue介绍185
10.1.3 全局变量187
10.2 Upvalue底层支持189
10.2.1 修改closure结构体189
10.2.2 Lua闭包支持191
10.2.3 Go闭包支持192
10.3 Upvalue相关指令195
10.3.1 GETUPVAL195
10.3.2 SETUPVAL196
10.3.3 GETTABUP197
10.3.4 SETTABUP199
10.3.5 JMP200
10.4 测试本章代码202
10.5 本章小结203
第11章 元编程205
11.1 元表和元方法介绍205
11.1.1 元表206
11.1.2 元方法206
11.2 支持元表207
11.3 调用元方法208
11.3.1 算术元方法209
11.3.2 长度元方法211
11.3.3 拼接元方法211
11.3.4 比较元方法212
11.3.5 索引元方法214
11.3.6 函数调用元方法216
11.4 扩展LuaAPI217
11.4.1 GetMetatable()218
11.4.2 SetMetatable()218
11.5 测试本章代码219
11.6 本章小结222
第12章 迭代器223
12.1 迭代器介绍223
12.2 next()函数226
12.2.1 修改luaTable结构体227
12.2.2 扩展LuaAPI228
12.2.3 实现next()函数229
12.3 通用for循环指令229
12.4 测试本章代码232
12.5 本章小结234
第13章 异常和错误处理235
13.1 异常和错误处理介绍235
13.2 异常和错误处理API237
13.2.1 Error()238
13.2.2 PCall()239
13.3 error()和pcall()函数240
13.4 测试本章代码241
13.5 本章小结242
第三部分 Lua语法和编译器
第14章 词法分析245
14.1 编译器介绍245
14.2 Lua词法介绍247
14.3 实现词法分析器251
14.3.1 定义Token类型252
14.3.2 空白字符254
14.3.3 注释256
14.3.4 分隔符和运算符256
14.3.5 长字符串字面量258
14.3.6 短字符串字面量259
14.3.7 数字字面量262
14.3.8 标识符和关键字263
14.4 LookAhead()和其他方法264
14.5 测试本章代码265
14.6 本章小结267
第15章 抽象语法树269
15.1 抽象语法树介绍269
15.2 Chunk和块270
15.3 语句272
15.3.1 简单语句273
15.3.2 while和repeat语句273
15.3.3 if语句274
15.3.4 数值for循环语句275
15.3.5 通用for循环语句275
15.3.6 局部变量声明语句276
15.3.7 赋值语句277
15.3.8 非局部函数定义语句278
15.3.9 局部函数定义语句279
15.4 表达式280
15.4.1 简单表达式280
15.4.2 运算符表达式281
15.4.3 表构造表达式281
15.4.4 函数定义表达式282
15.4.5 前缀表达式283
15.4.6 圆括号表达式284
15.4.7 表访问表达式284
15.4.8 函数调用表达式285
15.5 本章小结286
第16章 语法分析287
16.1 语法分析介绍287
16.1.1 歧义288
16.1.2 前瞻和回溯289
16.1.3 解析方式290
16.2 解析块290
16.3 解析语句293
16.3.1 简单语句294
16.3.2 if语句296
16.3.3 for循环语句297
16.3.4局部变量声明和函数定义语句299
16.3.5 赋值和函数调用语句300
16.3.6 非局部函数定义语句302
16.4 解析表达式303
16.4.1 运算符表达式304
16.4.2 非运算符表达式306
16.4.3 函数定义表达式307
16.4.4 表构造表达式308
16.4.5 前缀表达式310
16.4.6 圆括号表达式311
16.4.7 函数调用表达式312
16.4.8 表达式优化313
16.5 测试本章代码315
16.6 本章小结316
第17章 代码生成317
17.1 定义funcInfo结构体317
17.1.1 常量表318
17.1.2 寄存器分配319
17.1.3 局部变量表320
17.1.4 Break表323
17.1.5 Upvalue表324
17.1.6 字节码325
17.1.7 其他信息327
17.2 编译块327
17.3 编译语句329
17.3.1 简单语句330
17.3.2 while和repeat语句331
17.3.3 if语句333
17.3.4 for循环语句334
17.3.5 局部变量声明语句335
17.3.6 赋值语句337
17.4 编译表达式339
17.4.1 函数定义表达式340
17.4.2 表构造表达式341
17.4.3 运算符表达式343
17.4.4 名字和表访问表达式345
17.4.5 函数调用表达式346
17.5 生成函数原型347
17.6 使用编译器349
17.7 测试本章代码350
17.8 本章小结350
第四部分 Lua标准库
第18章 辅助API和基础库353
18.1 Lua标准库介绍353
18.2 辅助API355
18.2.1 增强版方法357
18.2.2 加载方法358
18.2.3 参数检查方法359
18.2.4 标准库开启方法360
18.3 基础库361
18.3.1 基础库介绍362
18.3.2 基础库实现362
18.4 测试本章代码365
18.5 本章小结366
第19章 工具库367
19.1 数学库367
19.2 表库369
19.3 字符串库372
19.4 UTF-8库374
19.5 OS库376
19.6 本章小结379
第20章 包和模块381
20.1 包和模块介绍381
20.2 实现包库386
20.3 测试本章代码391
20.4 本章小结392
第21章 协程393
21.1 协程介绍393
21.2 协程API396
21.2.1 支持线程类型396
21.2.2 支持协程操作398
21.3 实现协程库400
21.4 测试本章代码403
21.5 本章小结404
附录A Lua虚拟机指令集405
附录B Lua语法EBNF描述407
后记409精彩书摘
想要了解Java虚拟机的内部运行原理,阅读虚拟机规范、书籍、源码是一种常见的途径,而从零开始自己动手编写一个实验室性质的Java虚拟机,也许会是一种更加有趣且有效的学习路径。如果不考虑Java庞大类库的实现和JVM的实际生产力需求,仅是去“正确地”实现一台Java虚拟机,其实并不如大多数人所想的那样高深和困难——只需正确读取Class文件中每一条字节码指令,并且能正确执行这些指令所蕴含的操作即可。通过《自己动手实现Lua:虚拟机、编译器和标准库》,您可以跟随作者的思路和指引,一步步完成Java虚拟机的各个组成部分,在动手的过程中了解Java虚拟机的运作原理。
——周志明《深入理解Java虚拟机:JVM高级特性与最佳实践》作者
这是国内第一本以实战模式描述JVM原理的书!秀宏对JVM进行了大量研究,在书中深入浅出地分析了class文件的数据结构和JVM的基本原理,并使用Go语言用不到1万行的程序代码就实现了JVM的基本模型,是Java爱好者了解JVM实现原理的一本好书。实战才是最有效的掌握知识的手段,快快动手,实现属于自己的Java虚拟机吧!
——凌聪乐元素CTO
JVM对大多数的Java开发人员来说(无论是初出茅庐的菜鸟还是工作多年的老手),可能仍是一个神秘、高深莫测的黑匣子。《自己动手实现Lua:虚拟机、编译器和标准库》作者通过实践的方式,一步步带领大家饶有趣味地揭开JVM的神秘面纱,极大加深程序员对Java的理解,进而构建更加合理高效的代码。
——金智伟钱咸升(北京)网络科技股份公司CTO
Lua被广泛应用于游戏开发,是一种非常简单有效的脚本语言,但国内深入讲解Lua虚拟机的书籍几乎没有。秀宏用扎实的技术能力,不仅对Lua从语法、数据结构到原理进行了深度的分析,还使用Go语言一步一步地教会读者还原一个LuaVM的实现过程。在区块链和DSL流行的当下,VM作为底层技术架构的重要性凸显,而这《自己动手实现Lua:虚拟机、编译器和标准库》对于VM的开发来说是非常好的教材。赶紧阅读此书、下载代码、开始动手属于自己的VM吧!这个过程一定能让你受益匪浅!
——凌聪乐元素CTO
Go语言诞生10年有余,日渐成熟。Go在云计算和区块连等领域成为事实上的首选语言,七牛云几乎所有基础设施都是使用Go语言构建的。《自己动手实现Lua》一本难得的Go语言实战的图书,通过它你将一步步学习和掌握如何用Go去构建一门商业成熟的语言。
——许式伟七牛云创始人
脚本语言,从源代码到真正执行指定功能,到底经历了什么样的过程?你是不是探究过?编译原理教程很多,不过多以理论为主。《自己动手实现Lua:虚拟机、编译器和标准库》以Lua语言为研究对象,以Go为实现工具,步步为营,带我们完整实现了Lua虚拟机、编译器和标准库,让读者能知其然,而且知其所以然。相信读完之后,一方面,你能对Lua背后的机制了如指掌,另一方面,再看其他脚本语言应该也不会感觉神秘了。说不定,你也能设计并实现一门自己的脚本语言。
——臧秀涛InfoQ副总编
Lua是一种轻量小巧的脚本语言,非常非常适合超高性能的Web网关型服务、轻量级Web应用、Web页面渲染类应用等,搭建超高性能和并发服务。实际场景中,我们使用OpenResty和Lua语言构建过百亿级接口类服务和十亿级页面渲染类服务,且实现了复杂的业务逻辑,在用Lua实现时我们也踩了很多坑。《自己动手实现Lua:虚拟机、编译器和标准库》教大家如何动手实现Lua语言,知其所以然,能让大家更好地使用Lua这把瑞士军刀解决更多场景的问题。市面上的Lua书籍本身就少,大家可以在学习Lua的过程中配合《自己动手实现Lua:虚拟机、编译器和标准库》以达到更好的学习效果。
——张开涛《亿级流量网站架构》作者
前言/序言
为什么编写《自己动手实现Lua:虚拟机、编译器和标准库》
Lua是一门强大、高效、轻量、可嵌入的脚本语言。Lua语言设计十分精巧,在一个很小的内核上可以支持函数式编程、面向对象编程、元编程等多种编程范式。以《自己动手实现Lua:虚拟机、编译器和标准库》完稿时的最新版本Lua5.3.4为例,全部代码(包括Lua虚拟机、编译器、标准库等)仅有2万多行,这其中还包括注释和空行。
Lua语言大约于1993年诞生于巴西PUC-Rio大学,之后在游戏领域大放异彩,被很多游戏客户端选为脚本语言,比如知名游戏《魔兽世界》《模拟城市4》《愤怒的小鸟》等。很多流行的游戏引擎也选择Lua作为脚本语言,比如CryENGINE2、Cocos2d-x及CoronaSDK等。另外,也有很多游戏服务端采用C/C++搭配Lua的开发模式。除了游戏领域,Lua语言在其他地方也有很多应用,例如被广泛使用的NoSQL数据库Redis就使用Lua作为脚本语言扩展其能力。
相信自己动手设计并实现一门编程语言是每个程序员都会有的一个梦想,目前国内也已经出版或引进了一些指导读者自己实现编程语言的书籍。不过这些书籍要么只介绍了语言实现环节中的一小部分,无法纵观全局;要么只讨论某种大幅裁减后的简化语言,离真正的工业语言还有一定距离。例如,我自己的《自己动手写Java虚拟机》,只讨论了Java虚拟机实现,没有涉及Java编译器和Java标准库。
如上所述,之所以选择Lua语言,就是因为它足够小巧,并且有很好的流行度。麻雀虽小,五脏俱全,这使得我们可以在一《自己动手实现Lua:虚拟机、编译器和标准库》的篇幅范围内覆盖虚拟机、编译器、标准库这三个方面的内容。希望读者可以通过《自己动手实现Lua:虚拟机、编译器和标准库》完整体验一门编程语言的实现过程,为将来打造属于自己的语言做好准备。这正是《自己动手实现Lua:虚拟机、编译器和标准库》的与众不同之处。
《自己动手实现Lua:虚拟机、编译器和标准库》主要内容
《自己动手实现Lua:虚拟机、编译器和标准库》主要内容可以分为四个部分:第一部分(第1章)为准备工作;第二部分(第2~13章)主要讨论Lua虚拟机和LuaAPI;第三部分(第14~17章)主要讨论Lua语法和编译器,第四部分(第18~21章)主要讨论Lua标准库。
《自己动手实现Lua:虚拟机、编译器和标准库》共21章,各章内容安排如下:
第一部分(准备)
第1章:准备工作。
准备编程环境,编写“Hello,World!”程序。
第二部分(Lua虚拟机和LuaAPI)
第2章:二进制chunk。
介绍Lua二进制chuck文件格式,编写代码解析二进制chunk文件。
第3章:指令集
介绍Lua虚拟机指令集和指令编码格式,编写代码对指令进行解码。
第4章:LuaAPI
初步介绍LuaAPI和LuaState,实现栈相关API方法。
第5章:Lua运算符
介绍Lua语言运算符,给LuaAPI添加运算符相关方法。
第6章:虚拟机雏形
初步实现Lua虚拟机,可以解释执行大约一半的Lua虚拟机指令。
第7章:表
介绍并实现Lua表、表相关API方法,以及表相关指令。
第8章:函数调用
介绍并实现Lua函数调用。
第9章:Go函数调用
介绍如何在Lua中调用Go语言函数。
第10章:闭包和Upvalue
介绍并实现闭包和Upvalue,以及Upvalue相关指令。
第11章:元编程
介绍并实现Lua元表、元方法及元编程。
第12章:迭代器
介绍并实现Lua迭代器。
第13章:异常和错误处理
介绍Lua异常和错误处理机制。
第三部分(Lua语法和编译器)
第14章:词法分析
介绍Lua语言词法规则,实现词法分析器。
第15章:抽象语法树
初步介绍Lua语言语法规则,定义抽象语法树。
第16章:语法分析
进一步介绍Lua语言语法规则,编写语法分析器。
第17章:代码生成
编写代码生成器。
第四部分(Lua标准库)
第18章:辅助API和基础库
介绍Lua辅助API和标准库,实现基础库。
第19章:工具库
介绍并实现数学、表、字符串、UTF-8、OS等标准库。
第20章:包和模块
介绍Lua包和模块机制,实现package标准库。
第21章:协程
介绍Lua协程,实现coroutine标准库。
《自己动手实现Lua:虚拟机、编译器和标准库》面向的读者
《自己动手实现Lua:虚拟机、编译器和标准库》假定读者已经了解Go语言和Lua语言,所以不会对这两种语言的语法进行专门介绍。《自己动手实现Lua:虚拟机、编译器和标准库》使用Go语言实现Lua解释器,但并没有用到特别高深的技术,加之Go语言语法比较简单,相信有C系列语言(比如C、C++、C#、Java等)基础的程序员都可以轻松读懂书中的代码。此外,如果读者更加熟悉Java语言,《自己动手实现Lua:虚拟机、编译器和标准库》也提供了Java版实现代码。简而言之,《自己动手实现Lua:虚拟机、编译器和标准库》主要面向以下三类读者:
对脚本语言实现原理感兴趣的读者。
对编译原理和高级语言虚拟机感兴趣的读者。
对Lua语言感兴趣,想探究其内部实现的读者。
如何阅读《自己动手实现Lua:虚拟机、编译器和标准库》
《自己动手实现Lua:虚拟机、编译器和标准库》内容主要围绕代码对Lua虚拟机、编译器和标准库展开讨论。《自己动手实现Lua:虚拟机、编译器和标准库》代码经过精心安排,除第1章外,每一章都建立在前一章的基础之上,但每一章又都可以单独编译和运行。建议读者从第1章开始,按顺序阅读《自己动手实现Lua:虚拟机、编译器和标准库》并学习每一章的代码。但也可以直接跳到感兴趣的章节进行阅读,必要时再阅读其他章节。
参考资料
相比C/C++、Java、Python等主流语言,Lua算是较为小众的语言,因此能够找到的介绍其内部实现原理和细节的资料并不多,这也是《自己动手实现Lua:虚拟机、编译器和标准库》写作的动机之一。除了Lua官方实现的源代码,《自己动手实现Lua:虚拟机、编译器和标准库》在写作过程中主要参考了下面这些资料:
《ProgramminginLua,FourthEdition》
《Lua5.3ReferenceManual》
《TheEvolutionofLua》
《TheImplementationofLua5.0》
《ANo-FrillsIntroductiontoLua5.1VMInstructions》
《Lua5.3BytecodeReferenc