12.8 切片 5:WHILE 回环与四则运算。
- WHILE 编成 L_loop: <cond→t> JF t, L_end <body> JMP L_loop L_end:,JF/JMP 双回填 - 四则 ADD/SUB/MUL/DIV(用例 5 循环体自增需要,同模式实现,用例 7 顺带点亮) - codegen_test:115 断言(用例 05 回环 JMP -8、07 四则+比较、08 TIME 常量表),ctest 9/9
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
/**
|
||||
* @file Codegen.cpp
|
||||
* @brief 寄存器码生成(12.8,切片 4:+ CMP_*、IF/ELSIF/ELSE)
|
||||
* @brief 寄存器码生成(12.8,切片 5:+ WHILE、四则运算)
|
||||
* @author
|
||||
* @date 2026-08-21
|
||||
*
|
||||
* @details 设计说明(详见 Doc/compiler/寄存器码.md):
|
||||
* - 切片 1~3:帧/字面量/MOVE/RET;全局数据区;NOT 与短路 AND/OR。
|
||||
* - 切片 4:比较 CMP_xx(两侧求值到临时);IF 编成
|
||||
* <cond→t> JF t, L_next <body> JMP L_end L_next: ... L_end:
|
||||
* 跳转偏移相对下一条指令(目标 = 当前 + 1 + off,见 Doc/isa/指令与映像.md)
|
||||
* - 切片 1~4:帧/字面量/MOVE/RET;全局数据区;NOT 与短路 AND/OR;CMP 与 IF。
|
||||
* - 切片 5:WHILE 编成
|
||||
* L_loop: <cond→t> JF t, L_end <body> JMP L_loop L_end:
|
||||
* (用例 5 循环体含自增,四则 ADD/SUB/MUL/DIV 同模式一并实现,用例 7 可测)
|
||||
* - 跳转偏移相对下一条指令(目标 = 当前 + 1 + off,见 Doc/isa/指令与映像.md)
|
||||
* - 其余构造报 codegen error(后续切片展开)
|
||||
*
|
||||
* 函数清单:
|
||||
@@ -20,11 +21,12 @@
|
||||
* - find_pou 按名查 POU AST
|
||||
* - build_function 编译一个 POU 的语句体(帧寄存器分配)
|
||||
* - begin_stmt / alloc_temp 临时寄存器:语句内递增、语句结束复用基址
|
||||
* - compile_stmt 语句编译(切片 4:赋值 / IF)
|
||||
* - compile_stmt 语句编译(切片 5:赋值 / IF / WHILE)
|
||||
* - compile_if IF/ELSIF/ELSE:条件链 + 分支尾部 JMP,JF/JMP 回填
|
||||
* - compile_while WHILE:L_loop + 条件 JF + 体 + JMP 回环
|
||||
* - store_target 赋值左值:STORE_* 到全局槽
|
||||
* - compile_expr 表达式编译到寄存器(含 CMP_xx / NOT / 短路 AND/OR)
|
||||
* - cmp_op 比较符 → CMP_xx 操作码
|
||||
* - compile_expr 表达式编译到寄存器(含 CMP/算术/NOT/短路 AND/OR)
|
||||
* - cmp_op / arith_op 比较符/算术符 → 操作码
|
||||
* - load_op / store_op 按 io 绑定选读取/写入操作码
|
||||
* - global_offset 逻辑槽号 → 数据区字节偏移
|
||||
* - patch_jump 回填跳转偏移(相对下一条指令)
|
||||
@@ -246,8 +248,11 @@ namespace {
|
||||
if (st.kind == StmtKind::If) {
|
||||
return compile_if(f, st);
|
||||
}
|
||||
if (st.kind == StmtKind::While) {
|
||||
return compile_while(f, st);
|
||||
}
|
||||
if (st.kind != StmtKind::Assign) {
|
||||
return fail("statement not supported in slice 4");
|
||||
return fail("statement not supported in slice 5");
|
||||
}
|
||||
const auto it = f.regs.find(st.target);
|
||||
if (it == f.regs.end()) {
|
||||
@@ -258,6 +263,35 @@ namespace {
|
||||
return compile_expr(f, *st.value, rd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 编译 WHILE
|
||||
* @details L_loop: <cond→t> JF t, L_end <body> JMP L_loop L_end:
|
||||
* 条件 JF 与回环 JMP 双回填
|
||||
* @param f 当前函数
|
||||
* @param st WHILE 语句 AST
|
||||
* @return true 成功;false(err 已写)
|
||||
*/
|
||||
bool compile_while(FuncCtx& f, const Stmt& st) {
|
||||
const size_t loop = f.code.size();
|
||||
const uint8_t t = alloc_temp(f);
|
||||
if (!compile_expr(f, *st.cond, t)) {
|
||||
return false;
|
||||
}
|
||||
const size_t jf_idx = f.code.size();
|
||||
f.code.push_back(isa::enc_jc(isa::Op::JF, t, 0)); // 假 → L_end
|
||||
for (const Stmt& s : st.body) {
|
||||
begin_stmt(f);
|
||||
if (!compile_stmt(f, s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const size_t jmp_idx = f.code.size();
|
||||
f.code.push_back(isa::enc_jmp(0)); // 回环
|
||||
patch_jump(f, jmp_idx, loop);
|
||||
patch_jump(f, jf_idx, f.code.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 编译 IF / ELSIF / ELSE
|
||||
* @details 每分支:<cond→t> JF t, L_next → <body> → JMP L_end;
|
||||
@@ -369,6 +403,19 @@ namespace {
|
||||
}
|
||||
return fail("no register or slot for '" + e.name + "'");
|
||||
}
|
||||
if (e.kind == ExprKind::Add || e.kind == ExprKind::Sub ||
|
||||
e.kind == ExprKind::Mul || e.kind == ExprKind::Div) {
|
||||
const uint8_t l = alloc_temp(f);
|
||||
if (!compile_expr(f, *e.lhs, l)) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t r = alloc_temp(f);
|
||||
if (!compile_expr(f, *e.rhs, r)) {
|
||||
return false;
|
||||
}
|
||||
f.code.push_back(isa::enc_rrr(arith_op(e.kind), rd, l, r));
|
||||
return true;
|
||||
}
|
||||
if (e.kind == ExprKind::Cmp) {
|
||||
const uint8_t l = alloc_temp(f);
|
||||
if (!compile_expr(f, *e.lhs, l)) {
|
||||
@@ -423,6 +470,21 @@ namespace {
|
||||
static_cast<uint8_t>((static_cast<uint16_t>(off) >> 8) & 0xFFu));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 算术运算 → 操作码
|
||||
* @param k 表达式种类(Add/Sub/Mul/Div)
|
||||
* @return 对应操作码
|
||||
*/
|
||||
isa::Op arith_op(ExprKind k) const {
|
||||
switch (k) {
|
||||
case ExprKind::Add: return isa::Op::ADD;
|
||||
case ExprKind::Sub: return isa::Op::SUB;
|
||||
case ExprKind::Mul: return isa::Op::MUL;
|
||||
case ExprKind::Div: return isa::Op::DIV;
|
||||
default: return isa::Op::ADD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 比较符 → CMP_xx 操作码
|
||||
* @param op 比较运算
|
||||
|
||||
Reference in New Issue
Block a user