C++实现编译器(9): 函数与栈帧
参照《Writing An Interpreter/Compiler In Go》,改用C++实现。
引言
本篇对应的源码位于目录: src/08/
函数部分是最重要也是最难的部分,随着函数的编译需要切换编译作用域,而函数的递归和互相调用则需要切换调用栈环境,引入了栈帧
。
欢迎订阅公众号, 点击 MinYiLife
参照《Writing An Interpreter/Compiler In Go》,改用C++实现。
本篇对应的源码位于目录: src/08/
函数部分是最重要也是最难的部分,随着函数的编译需要切换编译作用域,而函数的递归和互相调用则需要切换调用栈环境,引入了栈帧
。
参照《Writing An Interpreter/Compiler In Go》,改用C++实现。
本篇对应的源码位于目录: src/07/
src
|07
| |token
| | |token.hpp
| |evaluator
| | |evaluator.hpp
| | |builtins.hpp
| |CMakeLists.txt
| |test
| | |lexer_test.hpp
| | |parser_test.hpp
| | |evaluator_test.hpp
| | |symbol_table_test.hpp
| | |vm_test.hpp
| | |objects_test.hpp
| | |ast_test.hpp
| | |code_test.hpp
| | |compiler_test.hpp
| | |main.cpp
| |lexer
| | |lexer.hpp
| |repl
| | |repl.hpp
| |code
| | |code.hpp
| |objects
| | |objects.hpp
| | |environment.hpp
| |parser
| | |parser.hpp
| | |parser_tracing.hpp
| |vm
| | |vm.hpp
| |ast
| | |ast.hpp
| |main
| | |monkey.cpp
| |compiler
| | |symbol_table.hpp
| | |compiler.hpp
这里为虚拟机添加一个符号表
,用于绑定变量。
因为字节码每个操作码的操作数只能是整数,因此在符号表里面将变量和一个整数建立映射关系,然后通过这个整数来代表变量写到字节码。等到虚拟机解码执行的时候,这个数字就是这个变量解码后存储的索引,可以直接访问。
目前这个符号表是全局的,后续再处理非全局的。
增加对字符串、数组和哈希表的编译支持。
参照《Writing An Interpreter/Compiler In Go》,改用C++实现。
本篇对应的源码位于目录: src/06/
src
|06
| |token
| | |token.hpp
| |evaluator
| | |evaluator.hpp
| | |builtins.hpp
| |CMakeLists.txt
| |test
| | |lexer_test.hpp
| | |parser_test.hpp
| | |evaluator_test.hpp
| | |vm_test.hpp
| | |objects_test.hpp
| | |ast_test.hpp
| | |code_test.hpp
| | |compiler_test.hpp
| | |main.cpp
| |lexer
| | |lexer.hpp
| |repl
| | |repl.hpp
| |code
| | |code.hpp
| |objects
| | |objects.hpp
| | |environment.hpp
| |parser
| | |parser.hpp
| | |parser_tracing.hpp
| |vm
| | |vm.hpp
| |ast
| | |ast.hpp
| |main
| | |monkey.cpp
| |compiler
| | |compiler.hpp
之前字节码和编译器已经支持整数加法运算,现在添加对表达式和条件语句的支持,会涉及到编译顺序
的调整,执行条件语句的跳转指令
等。
老爷子今年六十岁,明天就要带八岁的小虎子去外甥家做客。
那天夜里在昏暗的灯光下,老头老太太还有小虎子围在桌子前交代事情。
老爷子巴巴的抽着旱烟,没有说话,明天去做客,但实在拿不出什么像样的礼物;好在外甥懂事,说了只要舅舅能来就敲锣打鼓放鞭炮热烈欢迎,不需要拿什么东西。
话虽然是这么说,但老爷子一辈子的人情世故,心想总不能失了礼。
参照《Writing An Interpreter/Compiler In Go》,改用C++实现。
本篇对应的源码位于目录: src/05/
src
|05
| |token
| | |token.hpp
| |evaluator
| | |evaluator.hpp
| | |builtins.hpp
| |CMakeLists.txt
| |test
| | |lexer_test.hpp
| | |parser_test.hpp
| | |evaluator_test.hpp
| | |vm_test.hpp
| | |objects_test.hpp
| | |ast_test.hpp
| | |code_test.hpp
| | |compiler_test.hpp
| | |main.cpp
| |lexer
| | |lexer.hpp
| |repl
| | |repl.hpp
| |code
| | |code.hpp
| |objects
| | |objects.hpp
| | |environment.hpp
| |parser
| | |parser.hpp
| | |parser_tracing.hpp
| |vm
| | |vm.hpp
| |ast
| | |ast.hpp
| |main
| | |monkey.cpp
| |compiler
| | |compiler.hpp
为了提高性能和移植性,在前面树遍历解释器基础上,引入虚拟机和字节码。
为了在代码结构和接口形式上都尽量保持和原有Go语言代码相近,多花了一些时间,因为Go原生带有切片、字节序大小端读写等封装好的功能,而在C++就需要自己去组装这些工具。
目前进度为止,虚拟机只支持通过字节码进行整数的加法操作。
参照《Writing An Interpreter/Compiler In Go》,改用C++实现。
本篇对应的源码位于目录: src/04/
04
|token
| |token.hpp
|evaluator
| |evaluator.hpp
| |builtins.hpp
|CMakeLists.txt
|test
| |lexer_test.hpp
| |parser_test.hpp
| |evaluator_test.hpp
| |objects_test.hpp
| |ast_test.hpp
| |main.cpp
|lexer
| |lexer.hpp
|repl
| |repl.hpp
|objects
| |objects.hpp
| |environment.hpp
|parser
| |parser.hpp
| |parser_tracing.hpp
|ast
| |ast.hpp
|main
| |monkey.cpp
这篇主要在现有框架上扩展一些功能:
len
,first
,rest
,push
,puts
参照《Writing An Interpreter/Compiler In Go》,改用C++实现。
本篇对应的源码位于目录: src/03/
03
|token
| |token.hpp
|evaluator
| |evaluator.hpp
|CMakeLists.txt
|test
| |lexer_test.hpp
| |parser_test.hpp
| |evaluator_test.hpp
| |ast_test.hpp
| |main.cpp
|lexer
| |lexer.hpp
|repl
| |repl.hpp
|objects
| |objects.hpp
| |environment.hpp
|parser
| |parser.hpp
| |parser_tracing.hpp
|ast
| |ast.hpp
|main
| |monkey.cpp
求值(Evaluation)
是解释器处理源代码过程的最后一步,求值过程决定了一门编程语言的解释方式。
参照《Writing An Interpreter/Compiler In Go》,改用C++实现。
本篇对应的源码位于目录: src/02/
02
|token
| |token.hpp
|CMakeLists.txt
|test
| |lexer_test.hpp
| |parser_test.hpp
| |ast_test.hpp
| |main.cpp
|lexer
| |lexer.hpp
|repl
| |repl.hpp
|parser
| |parser.hpp
| |parser_tracing.hpp
|ast
| |ast.hpp
|main
| |monkey.cpp
语法分析器
将输入的内容转换为对应的数据结构,具体就是将词法分析器得到的一系列词法Token转换为对应的数据结构,形成抽象语法树(AST)
。
使用yacc
、bison
、ANTLR
等语法分析器生成器工具,可以根据BNF或EBNF形式描述的语法构成,自动生成语法分析器。为了理解语法分析器的工作原理,不使用这些工具。
这里准备编写的语法分析器是递归下降语法分析器
,具体就是基于自上而下的运算符优先级分析法,其发明人是普拉特,又称普拉特语法分析器
。
Man Pages
是Linux系统常用的在线文档手册。
常说在Linux里不需要记住软件命令的用法,只要会找男人
就行了,指的就是查看这个man pages
文档。
Docker是比较常用的容器,常用于部署应用或作为开发环境,但一般的Docker镜像为了减少体积,不会带有Man Pages
文档手册。
有时候哪怕按照一般的做法使用yum
安装了man-pages
软件包,发现还是没有按预期安装文档,这是怎么回事呢?
PAM
指的是Pluggable Authentication Modules
,以可插拔模块的形式来帮助Linux管理系统的授权。
PAM
将系统授权相关的逻辑功能做成共享链接库(/usr/lib64/security/
)的形式,然后其他需要授权操作的程序只需要调用这个共享库即可。
对于管理员来说,正确的设置复杂授权等工作就变成了一个简单的管理配置文件的工作了。