130 lines
5.4 KiB
C++
130 lines
5.4 KiB
C++
/**
|
||
* @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/Parser.h"
|
||
#include "compiler/Project.h"
|
||
|
||
namespace compiler {
|
||
|
||
/**
|
||
* @brief 符号种类(与 Doc/初步计划.md 12.1 一致)。
|
||
* @details 各成员含义:
|
||
* - Global:全局变量(仅 gvl 顶层,编全局槽号)
|
||
* - External:VAR_EXTERNAL 引用(接全局同一槽,类型必须一致)
|
||
* - Local:POU 内部局部变量(12.8 分配槽)
|
||
* - Input / Output:POU 输入 / 输出参数
|
||
* - Pou:POU 登记(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);局部暂 0(12.8 分配)
|
||
std::string source_file; ///< 声明所在源文件
|
||
uint32_t line = 0; ///< 声明行号
|
||
uint32_t col = 0; ///< 声明列号
|
||
};
|
||
|
||
/**
|
||
* @brief FB 类型字段(实例布局用;v1 字段类型仅 BOOL/INT/TIME)。
|
||
*/
|
||
struct FbField {
|
||
std::string name; ///< 字段名
|
||
TypeKind type = TypeKind::Bool; ///< 字段类型(仅标量)
|
||
};
|
||
|
||
/**
|
||
* @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 校验。失败返回 false,err 前缀 "link error"。
|
||
* @param proj 工程定义(toml 解析结果)
|
||
* @param units 全部源文件的 AST(compile_files 集合逐一 load_unit 得到)
|
||
* @param out 链接结果(各字段先清空后填充)
|
||
* @param err 错误输出;可为 nullptr(静默)
|
||
* @return true 成功;false 失败(err 已写)
|
||
*/
|
||
bool link_project(const Project& proj, const std::vector<SourceUnit>& units,
|
||
LinkResult* out, std::string* err);
|
||
|
||
/**
|
||
* @brief 读取并解析一个 .st 文件成 SourceUnit。
|
||
* @param path .st 文件路径
|
||
* @param out 输出 SourceUnit(path + 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);
|
||
}
|