首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
逆向工程
发新帖
0
2
[分享]简单编译器实现
发表于: 2026-4-20 16:19
1868
[分享]简单编译器实现
mb_binusgki
2026-4-20 16:19
1868
# 前言 前几小结实现了简单的代码解释器、词法解析器,由以上基础铺垫 本节笔者将实现一个简易的编译器,实现效果为:编写简单代码 "a = 1 + 2" 编译器需要使用词法解析器将其解析成 token 序列,再将 token 序列建立 AST 节点,例如: ``` = / \ a + / \ 1 2 ``` 这个“树结构”,就是 AST(Abstract Syntax Tree,抽象语法树) 其中涉及数字节点、二元表达式以及赋值节点 为什么要建立 AST 节点呢? 因为当一个表达式 a = 1 + 2 程序并不知道先处理 = 还是处理 + ,以后还会实现更复杂的表达式 AST 节点可以很好解决优先级处理问题 有了 AST 节点后就能编写代码生成器,将 AST 转换为 虚拟机指令(MOV / ADD),最后输出机器码即可放入之前写的解释器中运行 本节将以最简编译器的方式走通从源码到结果的全流程,大致流程如下: ``` ource Code(源码) ↓ Lexer(词法分析 把字符串 → 切成“最小语法单元”) ↓ Token(中间数据) ↓ Parser(语法分析) ↓ AST(抽象语法树) ↓ CodeGen(代码生成) ↓ 指令(IR / VM 指令) ↓ 执行(解释器 / 虚拟机) ↓ 结果 ``` # 一、词法分析 将调用上节的代码进行复用 ``` // 1. 词法分析 Lexer lexer(input); auto tokens = lexer.tokenize(); ``` # 二、语法分析 目前只处理了 + 和 - 操作 以及 数字 + 数字 的形式,其余可自行补充 ``` //语法解析 class Syntax { public: Syntax(const std::vector<Token>& tokens) : tokens(tokens), pos(0) { } //解析 AssignStmt parse() { AssignStmt stmt; // a stmt.name = consume(TOK_VAR).text; // = 这里没有保存值,只是“确认语法正确” consume(TOK_ASSIGN); // 1 + 2 解析表达式 stmt.expr = parseExpr(); return stmt; } private: std::vector<Token> tokens; size_t pos; //当前pos指向的token Token& peek() { return tokens[pos]; } //验证 + 前进 Token consume(TokenType type) { if (tokens[pos].type != type) { throw std::runtime_error("unexpected token"); } return tokens[pos++]; } // 只实现 1 + 2 这种 Expr* parseExpr() { //解析左边 Expr* left = parsePrimary(); //判断是否有 + if (peek().type == TOK_ADD) { //处理 + consume(TOK_ADD); //解析右边 Expr* right = parsePrimary(); //构建 BinaryExpr: 1+2 return new BinaryExpr('+', left, right); } //判断是否有 - if (peek().type == TOK_SUB) { //处理 - consume(TOK_SUB); //解析右边 Expr* right = parsePrimary(); //构建 BinaryExpr: 1+2 return new BinaryExpr('-', left, right); } return left; } //解析“最小单位” 把简单元素组合成表达式 Expr* parsePrimary() { if (peek().type == TOK_NUMBER) { //stoi: 字符转换整数 int v = std::stoi(consume(TOK_NUMBER).text); return new NumberExpr(v); } throw std::runtime_error("invalid expression"); } }; ``` # 三、代码生成 代码生成目前只支持 + 和 - 操作,剩余可自行添加 ``` class CodeGen { public: CodeGen(Assembler& as) : as(as) {} void gen(const AssignStmt& stmt) { //把表达式计算结果放到 R0 genExpr(stmt.expr); // 这里只是演示,没有变量表 // 先直接 print 结果 PRINT(as, R0); HALT(as); } private: Assembler& as; //递归生成表达式的指令 void genExpr(Expr* expr) { //数字 //dynamic_cast: 判断 expr 是不是 NumberExpr 类型 if (auto num = dynamic_cast<NumberExpr*>(expr)) { //生成:MOV R0, 1 MOVI(as, R0, num->value); } //二元表达式 expr 是 1 + 2 else if (auto bin = dynamic_cast<BinaryExpr*>(expr)) { // 左边 → R0 genExpr(bin->left); // 右边 → R1 int value = getNumber(bin->right);//把右边表达式“强行当成数字” MOVI(as, R1, value); ////处理+ //if (bin->op == '+') { // ADDR(as, R0, R1); //} switch (bin->op) { case '+': { ADDR(as, R0, R1); break; } case '-': { SUBR(as, R0, R1); break; } /*case '*': { ADDR(as, R0, R1); break; } case '/': { ADDR(as, R0, R1); break; }*/ } } } //把表达式“强行当成数字” int getNumber(Expr* expr) { if (auto num = dynamic_cast<NumberExpr*>(expr)) { return num->value; } throw std::runtime_error("only support number"); } }; ``` # 四、测试 当前测试为简单表达式 "a = 10 - 2" ,运行后可在结果寄存器 R0 得到正确结果 8 ``` int main() { std::string input = "a = 10 - 2"; // 1. 词法分析 Lexer lexer(input); auto tokens = lexer.tokenize(); // 2. 语法分析 Syntax parser(tokens); AssignStmt stmt = parser.parse(); // 3. 生成代码: AST → 虚拟机指令(MOV / ADD) Assembler as; CodeGen gen(as); gen.gen(stmt); as.patch(); // 4. 调用循环解释器执行代码 VM vm = {}; LoopInterpreter(vm, as.getData()); } ``` # 总结 本节做了简单编译器的实现,用最小化的方式走通解释器的基础流程,欢迎讨论 如有错漏 请留言!
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
#调试逆向
#系统底层
#软件保护
#VM保护
#加密算法
#问题讨论
#其他内容
收藏
・
0
点赞
・
2
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
十年后
感谢你分享这么好的资源!
2026-4-21 20:50
勒LI
感谢你分享这么好的资源!
2026-4-20 16:25
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
2
)
LyOnline
雪 币:
220
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
10
粉丝
0
关注
私信
LyOnline
2
楼
你这不叫编译器,你这叫语法解析器
2026-4-23 14:44
0
mb_binusgki
雪 币:
390
能力值:
( LV1,RANK:0 )
在线值:
发帖
29
回帖
6
粉丝
21
关注
私信
mb_binusgki
3
楼
LyOnline
你这不叫编译器,你这叫语法解析器
是的 前半段的Lexer只负责分析语法,真正编译成机器码的过程在CodeGen 第三部分, 最后由自定义的解释器解释
2026-4-23 21:34
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
mb_binusgki
29
发帖
6
回帖
0
RANK
关注
私信
他的文章
[分享]注册表回调内核通信
376
[分享]简单编译器实现
1867
[分享]Lexer简单词法解析器入门
1231
[分享]vm解释器入门2
1288
[分享]vm解释器入门
1587
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部