Files
Interpreter/compiler/include/compiler/Linker.h
T

130 lines
5.4 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/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 类型字段(实例布局用;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 校验。失败返回 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,
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);
}