阶段3-1:编译器语言层 V2 完成(19 类型/字面量扩展/禁隐式转换/配置驱动 FB)

Lexer V2:
- 19 类型关键字(BOOL..DT);FB 名不再设关键字(IDENT)
- FLOAT_LIT(1.5/2.5e3)、进制前缀(2#/8#/16# 换算十进制)
- 日期字面量 D#/TOD#/DT#(历法换算 1970 纪元、闰年、值域检查)

Parser V2:
- TypeRef 字符串化(TypeKind{Scalar,FbBuiltin,FbUser},名字小写)
- ExprKind 增 LitReal/LitDate/LitTod/LitDt;Expr.double_value
- IDENT 类型统一 FbUser(内建判定在 Linker 查 fb 表)

Typecheck V2:
- TType 19 + Unresolved(字面量未定型)
- 禁隐式转换(赋值/算术/比较严格同型)
- resolve_to:未定型→消费点定型+值域检查(BOOL 0/1、无符号负数、
  溢出、浮点仅 REAL/LREAL);算术按 kind 允许(TIME 仅 ±)
- Call 实参按函数参数类型;check_project 加 cfg

Linker V2:
- FbField.type_name 字符串化;内建 FB 布局查 machine.toml [[fb]] 表
  (删 8 个硬编码布局,带缓存);link_project 加 cfg

Codegen V2:
- 浮点/日期字面量(LOADK func 8/4/4/6;LitReal 按 REAL 装载,LREAL TODO)
- 算术/比较 func 按操作数类型(expr_func)
- TypeKind 连锁适配

main.cpp:link/check 传 cfg;--disasm 头 22 字段逐行中文注释(L5)
+ slots 节;StbView 补 offset_const/offset_funcs

测试适配:parser/linker/typecheck/vm/cases 适配新接口与 V2 语义。
ctest 11/13(vm_cycles/cases_all 待阶段 4)。codegen_test 仍剥离(阶段 3-2 重写)。
This commit is contained in:
2026-08-26 09:29:31 +08:00
parent 6ab2195a6b
commit 6be2873c88
16 changed files with 863 additions and 336 deletions
+58 -28
View File
@@ -29,6 +29,7 @@
#include <cctype>
#include <cstdio>
#include <cstring>
#include <functional>
#include <map>
#include <string>
@@ -216,16 +217,6 @@ namespace {
return t ? static_cast<uint8_t>(t->func) : 0;
}
/// TypeKind 枚举 → 配置类型名(BOOL/INT/TIME;其他回退 INT)。
static const char* type_kind_name(TypeKind k) {
switch (k) {
case TypeKind::Bool: return "BOOL";
case TypeKind::Int: return "INT";
case TypeKind::Time: return "TIME";
default: return "INT";
}
}
const POU* find_pou(const std::string& name) const {
for (const SourceUnit& u : units_) {
for (const POU& p : u.ast.pous) {
@@ -258,19 +249,16 @@ namespace {
return r;
}
/// 变量名 → 语言类型名(局部声明)。
/// 变量名 → 语言类型名(局部声明;标量 = d.type.name 小写)。
std::string type_name_of_var(const POU& pou, const std::string& name) const {
for (const VarBlock& b : pou.blocks) {
for (const VarDecl& d : b.vars) {
if (d.name == name) {
if (d.type.kind == TypeKind::Bool) return "BOOL";
if (d.type.kind == TypeKind::Int) return "INT";
if (d.type.kind == TypeKind::Time) return "TIME";
return "INT";
return d.type.kind == TypeKind::Scalar ? d.type.name : "int";
}
}
}
return "INT";
return "int";
}
bool build_function(const POU& pou, FuncCtx* f) {
@@ -496,11 +484,29 @@ namespace {
bool compile_expr(FuncCtx& f, const Expr& e, uint8_t rd) {
if (e.kind == ExprKind::LitBool || e.kind == ExprKind::LitInt ||
e.kind == ExprKind::LitTime) {
const char* type_name = e.kind == ExprKind::LitBool ? "BOOL"
: e.kind == ExprKind::LitInt ? "INT"
: "TIME";
const size_t s = E_imm(f, "LOADK", rd, const_id(e.int_value));
e.kind == ExprKind::LitTime || e.kind == ExprKind::LitReal ||
e.kind == ExprKind::LitDate || e.kind == ExprKind::LitTod ||
e.kind == ExprKind::LitDt) {
const char* type_name = "INT";
int64_t value = e.int_value;
switch (e.kind) {
case ExprKind::LitBool: type_name = "BOOL"; break;
case ExprKind::LitInt: type_name = "INT"; break;
case ExprKind::LitTime: type_name = "TIME"; break;
case ExprKind::LitReal: {
// TODO(V2): 浮点字面量按目标类型装载(REAL/LREAL 位模式不同),
// 需 compile_expr 携带目标 func;当前按 REALfloat32)装载
type_name = "REAL";
float fv = static_cast<float>(e.double_value);
std::memcpy(&value, &fv, sizeof fv);
break;
}
case ExprKind::LitDate: type_name = "DATE"; break;
case ExprKind::LitTod: type_name = "TOD"; break;
case ExprKind::LitDt: type_name = "DT"; break;
default: break;
}
const size_t s = E_imm(f, "LOADK", rd, const_id(value));
set_func(f.code.data() + s, func_of_name(type_name));
return true;
}
@@ -560,7 +566,7 @@ namespace {
return false;
}
const size_t s = E_rrr(f, arith_name(e.kind), rd, l, r);
set_func(f.code.data() + s, func_of_name("INT"));
set_func(f.code.data() + s, expr_func(f, *e.lhs, *e.rhs));
return true;
}
if (e.kind == ExprKind::Cmp) {
@@ -573,7 +579,7 @@ namespace {
return false;
}
const size_t s = E_rrr(f, cmp_name(e.op), rd, l, r);
set_func(f.code.data() + s, func_of_name("INT"));
set_func(f.code.data() + s, expr_func(f, *e.lhs, *e.rhs));
return true;
}
if (e.kind == ExprKind::Not) {
@@ -625,6 +631,32 @@ namespace {
return fail("expression not supported");
}
/// 表达式类型 func(算术/比较用):VarRef 取 reg_func/全局;
/// 嵌套表达式左右递归;字面量按装载类型(LitInt→INT、LitReal→REAL 等)。
uint8_t expr_func(const FuncCtx& f, const Expr& l, const Expr& r) const {
if (l.kind == ExprKind::VarRef) {
const auto tf = f.reg_func.find(l.name);
if (tf != f.reg_func.end()) {
return tf->second;
}
return func_of_global(l.name);
}
if (l.kind == ExprKind::LitBool || l.kind == ExprKind::LitInt ||
l.kind == ExprKind::LitTime || l.kind == ExprKind::LitReal ||
l.kind == ExprKind::LitDate || l.kind == ExprKind::LitTod ||
l.kind == ExprKind::LitDt) {
// 左是字面量 → 取右操作数(Typecheck 已定型同型)
if (r.kind == ExprKind::VarRef) {
const auto tf = f.reg_func.find(r.name);
if (tf != f.reg_func.end()) {
return tf->second;
}
return func_of_global(r.name);
}
}
return func_of_name("INT");
}
/// 全局变量 → func(查链接符号类型)。
uint8_t func_of_global(const std::string& name) const {
for (const Symbol& s : link_.globals) {
@@ -726,10 +758,9 @@ namespace {
inst.type_name = s.type_name;
int32_t off = 0;
for (const FbField& fd : lay->second.fields) {
const char* tn = type_kind_name(fd.type);
const TypeMeta tm = type_meta(cfg_, tn);
const TypeMeta tm = type_meta(cfg_, fd.type_name);
if (!tm) {
return fail("no type for fb field '" + std::string(tn) + "'");
return fail("no type for fb field '" + fd.type_name + "'");
}
off = static_cast<int32_t>(align_up(off, tm.width()));
inst.field_off[fd.name] = off;
@@ -739,8 +770,7 @@ namespace {
// 实例块对齐到 max(字段对齐)
uint32_t max_align = 1;
for (const FbField& fd : lay->second.fields) {
const char* tn = type_kind_name(fd.type);
const TypeMeta tm = type_meta(cfg_, tn);
const TypeMeta tm = type_meta(cfg_, fd.type_name);
max_align = max_align > tm.width() ? max_align : tm.width();
}
cur_addr = align_up(cur_addr, max_align);