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 重写)。
131 lines
5.5 KiB
C++
131 lines
5.5 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/MachineConfig.h"
|
||
#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 类型字段(实例布局用;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 校验。失败返回 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,
|
||
const MachineConfig& cfg, 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);
|
||
}
|