要编写简易编译器,应从词法分析和语法树构建入手。1. 词法分析是将源代码拆分为token的过程,可通过逐字符读取输入并识别关键字、标识符、运算符等实现;建议使用状态机手动实现,并记录token类型与值。2. 语法树(ast)是表示程序结构的树形结构,用于后续分析与生成代码;需定义文法并采用递归下降解析器构建,每种语法结构对应一种ast节点类型。3. 实现中常见问题包括token识别错误、语法解析混乱、ast构造复杂及程序运行失败,分别可通过完善测试用例、严格按文法规则编写函数、简化节点结构并使用智能指针、以及增加调试输出等方式解决。

写一个简易编译器,从词法分析和语法树构建入手是个不错的起点。这两个部分是整个编译流程中最基础也是最关键的环节,搞清楚它们的原理和实现方式,后面的工作才能顺利推进。

下面我会从实际操作的角度出发,讲讲怎么用 C++ 来做这件事,重点放在入门时容易理解的部分,不会一上来就整太复杂的理论。

1. 什么是词法分析?怎么做?
词法分析(Lexical Analysis)就是把源代码字符串拆成一个个“单词”,这些单词在编译术语里叫做Token。比如你写的
int a = 10;这句话会被拆成几个 Token:
int(关键字)、
a(标识符)、
=(运算符)、
10(数字字面量)、
;(分号)等。
立即学习“C++免费学习笔记(深入)”;
要自己实现一个词法分析器,最直接的方式就是逐字符读取输入,根据规则判断当前字符属于哪种 Token,并记录下来。

举个简单的例子:
std::string input = "int a = 10;";
我们可以写一个函数,按顺序读取每个字符,遇到字母开头就继续往后看是不是关键字或者变量名;遇到数字就一直读到不是数字为止;遇到空格就跳过等等。
常用的做法是使用状态机或者正则表达式来识别 Token,不过对于新手来说,先手动实现一个简单的状态机更容易理解。
几点建议:
- 每个 Token 至少应该包含类型和值两个信息。
- 注意处理多字符运算符,比如
==
、<=
这类。 - 空白符、注释一般在词法分析阶段就被忽略掉。
- 把 Token 存在一个列表中,供后续语法分析使用。
2. 语法树是什么?为什么要构建它?
语法树(Abstract Syntax Tree, AST)是用来表示程序结构的一种树形数据结构。它比原始代码更结构化,方便后续的语义分析、优化和生成目标代码。
比如这句代码:
a = b + c;
它的 AST 可能是一个赋值节点,左边是变量
a,右边是一个加法操作,包含两个子节点
b和
c。
构建 AST 的前提是有一个清晰的语法结构定义,也就是我们常说的文法(Grammar)。你可以自己设计一个小语言的文法,比如支持变量声明、赋值、简单表达式等。
例如,一个非常简化的文法可能像这样:
statement -> assignment
assignment -> ID '=' expression ';'
expression -> term (('+' | '-') term)*
term -> factor (('*' | '/') factor)*
factor -> ID | NUMBER | '(' expression ')'有了这个文法之后,就可以编写一个递归下降解析器(Recursive Descent Parser),一边检查语法是否正确,一边构建 AST 节点。
一些实用技巧:
- 每种语法结构对应一个 AST 类型,比如赋值节点、加法节点、变量引用节点等。
- 使用面向对象的方式设计 AST 结构比较直观。
- 在解析过程中维护一个 Token 列表指针,用来逐步匹配语法。
- 遇到错误时要有基本的报错机制,哪怕只是输出行号和错误类型。
3. 实现过程中的常见问题和解决思路
刚开始动手写的时候,会遇到不少坑。下面列出几个比较常见的问题和应对方法。
Token 分析不准确
- 原因:没有处理完所有可能的 Token 类型,或者优先级没考虑清楚。
- 解决办法:写测试用例,覆盖各种边界情况,比如连续多个空格、数字中有非法字符等。
语法解析逻辑混乱
- 原因:没有按照文法规则一步步写解析函数,或者递归调用顺序出错。
- 解决办法:严格按照文法规则写函数结构,每条规则一个函数,保持逻辑清晰。
AST 构造复杂难管理
- 原因:节点类型太多,继承关系复杂,内存管理混乱。
- 解决办法:简化结构,用统一接口或基类来管理不同类型的节点;用智能指针避免内存泄漏。
编译器跑不起来
- 原因:可能是某个步骤卡住了,比如 Token 没有正确结束,或者解析函数死循环。
- 解决办法:加调试输出,打印中间结果,看看程序到底运行到哪一步了。
基本上就这些内容了。词法分析和语法树构建看起来不复杂,但细节很多,尤其在处理各种边界条件的时候。新手可以从一个非常小的语言开始做起,慢慢扩展功能,边做边学效果最好。










