From 94634dc0b03611af73ce9e2e5cd07bb0e5722cbc Mon Sep 17 00:00:00 2001 From: chentianya Date: Wed, 26 Aug 2026 17:55:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A5=E9=AA=A42=EF=BC=9AVAR=5FTEMP=20?= =?UTF-8?q?=E9=93=BE=E6=8E=A5=E5=B1=82=EF=BC=88FB=20=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E6=8E=92=E9=99=A4=20Temp=20=E5=AD=97=E6=AE=B5=20+=20=E9=A1=B6?= =?UTF-8?q?=E5=B1=82=E9=98=B2=E5=BE=A1=E6=A0=A1=E9=AA=8C=20+=20scope=20?= =?UTF-8?q?=E7=AC=A6=E5=8F=B7=E6=98=A0=E5=B0=84=20Local=EF=BC=89+=20linker?= =?UTF-8?q?=5Ftest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compiler/src/Linker.cpp | 18 ++++++++---- tests/src/linker_test.cpp | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/compiler/src/Linker.cpp b/compiler/src/Linker.cpp index 03c54a3..12fcb4d 100644 --- a/compiler/src/Linker.cpp +++ b/compiler/src/Linker.cpp @@ -214,6 +214,11 @@ namespace { b.vars.empty() ? 0 : b.vars[0].line, b.vars.empty() ? 0 : b.vars[0].col); } + if (b.section == VarSection::Temp) { + return fail(u.path, "VAR_TEMP only allowed in POU", + b.vars.empty() ? 0 : b.vars[0].line, + b.vars.empty() ? 0 : b.vars[0].col); + } for (const VarDecl& d : b.vars) { if (out_->global_index.count(d.name)) { return fail(u.path, "duplicate global '" + d.name + "'", @@ -266,9 +271,11 @@ namespace { FbLayout lay; lay.type_name = p.name; for (const VarBlock& b : p.blocks) { - // 字段 = input / output / 内部 var;external 与 global 不是字段 + // 字段 = input / output / 内部 var;external/global/temp 不是字段 + //(VAR_TEMP 不持久,每次调用重新初始化,走帧寄存器) if (b.section == VarSection::External || - b.section == VarSection::Global) { + b.section == VarSection::Global || + b.section == VarSection::Temp) { continue; } for (const VarDecl& d : b.vars) { @@ -331,9 +338,10 @@ namespace { /** * @brief 建一个 POU 的局部符号 - * @details VAR/INPUT/OUTPUT → 对应种类;VAR_EXTERNAL → 查全局表接同一槽 - * (类型必须一致);FB 类型 → FbInstance + 布局(内建取冻结表, - * 用户类型查 fb_types);POU 内 VAR_GLOBAL → 拒绝 + * @details VAR/INPUT/OUTPUT → 对应种类;VAR_TEMP → Local(帧寄存器, + * 不持久);VAR_EXTERNAL → 查全局表接同一槽(类型必须一致); + * FB 类型 → FbInstance + 布局(内建取冻结表,用户类型查 fb_types); + * POU 内 VAR_GLOBAL → 拒绝 * @param file 出错文件 * @param p POU AST * @param sc 输出作用域(syms / fb_instances 被填充) diff --git a/tests/src/linker_test.cpp b/tests/src/linker_test.cpp index d23d79e..8f8fd20 100644 --- a/tests/src/linker_test.cpp +++ b/tests/src/linker_test.cpp @@ -70,6 +70,67 @@ static bool expect_link_err(const char* dir, const char* keyword) { return true; } +// ---- 0. VAR_TEMP:FB 布局排除 Temp、scope 符号为 Local ---- + +static bool test_var_temp() { + using namespace compiler; + const std::string toml = std::string(REPO_ROOT) + "/tests/cases/13_function_call/project.toml"; + Project p; + std::string err; + CHECK(parse_project(toml, &p, &err)); + SourceUnit u; + u.path = "main.st"; + CHECK(parse_pous("main.st", + "FUNCTION_BLOCK Foo\n" + "VAR_INPUT\n in : BOOL;\nEND_VAR\n" + "VAR_OUTPUT\n out : BOOL;\nEND_VAR\n" + "VAR\n state : BOOL;\nEND_VAR\n" + "VAR_TEMP\n tmp : INT;\nEND_VAR\n" + " out := tmp > 0;\n" + "END_FUNCTION_BLOCK\n" + "PROGRAM MAIN\nEND_PROGRAM", + &u.ast, &err)); + compiler::MachineConfig cfg; + std::string cerr; + CHECK(cfg.load(std::string(REPO_ROOT) + "/compiler/machine.toml", &cerr)); + LinkResult r; + std::vector units; + units.push_back(std::move(u)); + CHECK(link_project(p, units, cfg, &r, &err)); + + // FB 布局:字段 = input/output/内部 var,VAR_TEMP 不是字段 + const auto it = r.fb_types.find("foo"); + CHECK(it != r.fb_types.end()); + CHECK(it->second.fields.size() == 3); + CHECK(it->second.fields[0].name == "in"); + CHECK(it->second.fields[1].name == "out"); + CHECK(it->second.fields[2].name == "state"); + for (const FbField& f : it->second.fields) { + CHECK(f.name != "tmp"); + } + + // scope 符号:VAR_TEMP → Local(在 Foo 作用域) + bool saw_tmp = false; + bool saw_main = false; + for (const auto& sc : r.scopes) { + if (sc.name == "foo") { + for (const Symbol& s : sc.syms) { + if (s.name == "tmp") { + saw_tmp = true; + CHECK(s.kind == SymbolKind::Local); + CHECK(s.type_name == "int"); + } + } + } + if (sc.name == "main") { + saw_main = true; + } + } + CHECK(saw_tmp); + CHECK(saw_main); + return true; +} + // ---- 1. 用例 09:GVL + VAR_EXTERNAL 同一槽 ---- static bool test_case09() { @@ -229,6 +290,7 @@ static bool test_builtin() { } int main() { + if (!test_var_temp()) return 1; if (!test_case09()) return 1; if (!test_neg_cases()) return 1; if (!test_case16()) return 1;