主要观点:作者拥有计算机科学学位,曾学习编译器课程,上周末完成了从无到有编写编译器的尝试。以 Go 语言编写了将 BASIC 代码转换为 Go 代码的编译器toybasic
,并在 GitHub 上开源。
关键信息:
- 选择编写简单的
toybasic
编译器,受小时候学习的 BASIC 语言影响,基于 TinyBASIC 进行修改,去除了INPUT
语句。 - 编译器有三个阶段:词法分析器将源代码字符序列转换为有意义的标记序列;语法分析器根据标记构建语法树并检查语法正确性;编译器遍历语法树生成等效的 Go 代码。
- 词法分析器使用
nex
工具,通过确定性有限自动机(DFA)对语言进行标记化,配置文件指定正则表达式来捕获关键字和标识符。 - 语法分析器使用 Go 内置的
goyacc
,按照特定语法定义语言的语法,生成解析树,并通过opr
函数定义节点类型和形状。 - 每个节点类型都有
Generate
函数,知道如何将该节点转换为 Go 代码,并调用子节点的Generate
函数。 - 展示了一个简单的
example/hello.bas
程序及其输出,验证了编译器的功能。
重要细节:
lex
和yacc
自 1975 年起就开始帮助解决 C 语言中的问题,goyacc
是 Go 语言默认工具中的yacc
变体。- 语法定义中通过特殊语法指定语言的语法规则,并为每个相关符号提供 Go 代码片段来生成解析树。
- 定义了一个重要的属性表来指定树中每个节点需要填充的属性。
- 展示了
PrintOp
节点类型的示例代码,知道如何将其转换为 Go 代码中的fmt.Println
语句。 - 编写了一个使用
toybasic
中所有构造的 BASIC 程序来测试编译器,还验证了自己小时候写的第一个 BASIC 程序仍能正常工作。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。