Files
Interpreter/compiler/include/compiler/Linker.h
T
Admin 6be2873c88 阶段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 重写)。
2026-08-26 09:29:31 +08:00

131 lines
5.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file Linker.h
* @brief 符号表与链接
* @details 本文件定义链接阶段的输入 / 输出数据结构与对外接口(实现见 Linker.cpp):
* - Symbol / FbField / FbLayout / SourceUnit / LinkResult:符号与布局数据结构
* - link_project:链接主入口(校验 GVL、编全局槽号、解析 VAR_EXTERNAL、
* FB 实例与字段、函数循环调用检测、io 校验),失败 err 前缀 "link error"
* - load_unit:读取并解析一个 .st 文件成 SourceUnit
* - dump_symbols:符号表文本输出(全局表 + 各 POU 局部表)
* 流程与规则详见 Doc/compiler/符号表与链接.md。
* @author
* @date 2026-08-21
*/
#pragma once
#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include "compiler/MachineConfig.h"
#include "compiler/Parser.h"
#include "compiler/Project.h"
namespace compiler {
/**
* @brief 符号种类(与 Doc/初步计划.md 12.1 一致)。
* @details 各成员含义:
* - Global:全局变量(仅 gvl 顶层,编全局槽号)
* - ExternalVAR_EXTERNAL 引用(接全局同一槽,类型必须一致)
* - LocalPOU 内部局部变量(12.8 分配槽)
* - Input / OutputPOU 输入 / 输出参数
* - PouPOU 登记(PROGRAM / FUNCTION / FUNCTION_BLOCK
* - FbInstance:FB 实例(带布局,内建或用户类型)
* - Const:常量
*/
enum class SymbolKind { Global, External, Local, Input, Output, Pou, FbInstance, Const };
/**
* @brief 一个符号(全局槽表项或 POU 局部符号)。
*/
struct Symbol {
SymbolKind kind = SymbolKind::Local; ///< 符号种类
std::string name; ///< 符号名(小写)
std::string type_name; ///< 类型名:bool / int / time / fb 类型名(小写)
uint32_t address = 0; ///< 全局槽号(Global/External);局部暂 012.8 分配)
std::string source_file; ///< 声明所在源文件
uint32_t line = 0; ///< 声明行号
uint32_t col = 0; ///< 声明列号
};
/**
* @brief FB 类型字段(实例布局用;V2 字段类型为标量类型名小写)。
*/
struct FbField {
std::string name; ///< 字段名
std::string type_name; ///< 字段类型名(小写,如 "bool"/"time"
};
/**
* @brief 一个 FB 类型的字段布局(供实例分配与字段引用解析)。
*/
struct FbLayout {
std::string type_name; ///< 类型名(小写)
std::vector<FbField> fields; ///< 段序:input → output → 内部 var
};
/**
* @brief 一个源文件的 AST(供链接输入)。
*/
struct SourceUnit {
std::string path; ///< 源文件路径
Unit ast; ///< 解析出的 AST
};
/**
* @brief 链接结果:全局槽表 + FB 类型布局 + 各 POU 作用域 + 函数表顺序。
*/
struct LinkResult {
std::vector<Symbol> globals; ///< 全局槽表:下标即槽号(声明顺序)
std::map<std::string, uint32_t> global_index; ///< 名 → 槽号
std::map<std::string, FbLayout> fb_types; ///< 用户 FB 类型布局(按类型名)
/**
* @brief 每 POU 的局部符号与 FB 实例。
*/
struct PouScope {
std::string name; ///< POU 名
PouKind kind = PouKind::Program; ///< POU 种类
std::vector<Symbol> syms; ///< local/input/output/external/fb_instance
std::map<std::string, FbLayout> fb_instances; ///< 实例名 → 布局
};
std::vector<PouScope> scopes; ///< 全部 POU 作用域
std::vector<std::string> fn_order; ///< 函数表顺序(PROGRAM / FUNCTION / FUNCTION_BLOCK 名,收集序)
};
/**
* @brief 链接一个工程。
* @details 校验 GVL、定全局槽、解析 VAR_EXTERNAL、FB 实例与字段、函数循环调用检测、
* io 校验。失败返回 falseerr 前缀 "link error"。
* @param proj 工程定义(toml 解析结果)
* @param units 全部源文件的 ASTcompile_files 集合逐一 load_unit 得到)
* @param out 链接结果(各字段先清空后填充)
* @param err 错误输出;可为 nullptr(静默)
* @return true 成功;false 失败(err 已写)
*/
bool link_project(const Project& proj, const std::vector<SourceUnit>& units,
const MachineConfig& cfg, LinkResult* out, std::string* err);
/**
* @brief 读取并解析一个 .st 文件成 SourceUnit。
* @param path .st 文件路径
* @param out 输出 SourceUnitpath + ast
* @param err 错误输出;可为 nullptr(静默)
* @return true 成功;false 失败(透传 lex/syntax error
*/
bool load_unit(const std::string& path, SourceUnit* out, std::string* err);
/**
* @brief 符号表文本。
* @details 每行 "name kind type address file"(全局表 + 各 POU 局部表)。
* @param r 链接结果
* @return 多行文本:全局表逐行;每个 POU 以 "[名字]" 开头后接其局部符号行
*/
std::string dump_symbols(const LinkResult& r);
}