From 92e91350cc5711c4d8c69998c15e90e66d611953 Mon Sep 17 00:00:00 2001 From: chentianya Date: Wed, 26 Aug 2026 18:01:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A5=E9=AA=A44=EF=BC=9A=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=2021=5Fvar=5Ftemp=EF=BC=88VAR=5FTEMP=20=E6=AF=8F=E5=91=A8?= =?UTF-8?q?=E6=9C=9F=E9=87=8D=E7=BD=AE=E8=AF=AD=E4=B9=89=EF=BC=89+=20?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=9B=B4=E6=96=B0=20+=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20store=5Ftarget=20STORE=20=E7=BC=BA=20func=20=E9=9A=90?= =?UTF-8?q?=E8=97=8F=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/compiler/STCompiler使用说明.md | 2 +- Doc/compiler/符号表与链接.md | 2 +- Doc/全量验证表.md | 3 ++- compiler/src/Codegen.cpp | 3 ++- tests/cases/21_var_temp/EXPECTED.md | 8 ++++++++ tests/cases/21_var_temp/globals.st | 4 ++++ tests/cases/21_var_temp/main.st | 12 ++++++++++++ tests/cases/21_var_temp/motor.st | 18 ++++++++++++++++++ tests/cases/21_var_temp/project.toml | 11 +++++++++++ tests/src/cases_test.cpp | 1 + tests/src/compiler_test.cpp | 2 +- tests/src/vm_test.cpp | 21 +++++++++++++++++++-- 12 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 tests/cases/21_var_temp/EXPECTED.md create mode 100644 tests/cases/21_var_temp/globals.st create mode 100644 tests/cases/21_var_temp/main.st create mode 100644 tests/cases/21_var_temp/motor.st create mode 100644 tests/cases/21_var_temp/project.toml diff --git a/Doc/compiler/STCompiler使用说明.md b/Doc/compiler/STCompiler使用说明.md index decc268..04974f0 100644 --- a/Doc/compiler/STCompiler使用说明.md +++ b/Doc/compiler/STCompiler使用说明.md @@ -125,7 +125,7 @@ bit = 2 **POU**:`PROGRAM` / `FUNCTION` / `FUNCTION_BLOCK`(含对应 `END_*`)。 -**变量段**:`VAR` / `VAR_INPUT` / `VAR_OUTPUT` / `VAR_GLOBAL`(仅 `gvl.file` 顶层)/ `VAR_EXTERNAL`。 +**变量段**:`VAR` / `VAR_INPUT` / `VAR_OUTPUT` / `VAR_GLOBAL`(仅 `gvl.file` 顶层)/ `VAR_EXTERNAL` / `VAR_TEMP`(每次调用重新初始化,不跨周期持久;FB 内不占实例字段)。 **类型**:19 种(`BOOL`/`SINT`/`INT`/`DINT`/`LINT`/`BYTE`/`WORD`/`DWORD`/`LWORD`/`USINT`/`UINT`/`UDINT`/`ULINT`/`REAL`/`LREAL`/`TIME`/`DATE`/`TOD`/`DT`);内建 FB 15 条(`TON`/`TOF`/`TP`/`CTU`/`DCTU`/`CTD`/`DCTD`/`CTUD`/`DCTUD`/`R_TRIG`/`F_TRIG`/`SR`/`RS`/`PWM`/`RTC`,关键字,不可作变量名;FB 名三层判定:toml fb 表 → 用户 FB → 类型名)。 diff --git a/Doc/compiler/符号表与链接.md b/Doc/compiler/符号表与链接.md index 35be9dd..fad3401 100644 --- a/Doc/compiler/符号表与链接.md +++ b/Doc/compiler/符号表与链接.md @@ -91,7 +91,7 @@ struct Symbol { | 13 | PWM | in BOOL, pt TIME, duty REAL, q BOOL, et TIME | | 14 | RTC | enable BOOL, date DATE, tod TOD | -- 实例布局 = 类型字段表的一份拷贝;字段偏移编译期按 1/2/4/8 对齐计算(字段类型决定宽度),实例 = 槽表 1 条 +- 实例布局 = 类型字段表的一份拷贝(`VAR_TEMP` 不是字段,不持久,编译期映射为帧寄存器 + 每次调用初值装载);字段偏移编译期按 1/2/4/8 对齐计算(字段类型决定宽度),实例 = 槽表 1 条 ## 错误 diff --git a/Doc/全量验证表.md b/Doc/全量验证表.md index ef3393d..739e5d9 100644 --- a/Doc/全量验证表.md +++ b/Doc/全量验证表.md @@ -26,6 +26,7 @@ | 18_tof_ctu | 正例 | 编译+执行 | ok | | | 19_recursive_call | 负例 | 编译 | REJECTED ok | link error: recursive call | | 20_line1 | 正例 | 编译+执行 | ok | 真值表 4 行全对 | +| 21_var_temp | 正例 | 编译+执行 | ok | VAR_TEMP 每周期重置(a=10107/10108/10109) | ## line1 真值表(回放:io.input 顺序 EmergencyStop, I0_0;I0_1=0 未绑定) @@ -36,4 +37,4 @@ | 1 | 0 | 0 | ok(急停生效) | | 0 | 1 | 1 | ok | -**结论:20/20 用例符合期望,ctest 14/14,全部绿。** +**结论:21/21 用例符合期望,ctest 14/14,全部绿。** diff --git a/compiler/src/Codegen.cpp b/compiler/src/Codegen.cpp index 932c486..ba76c09 100644 --- a/compiler/src/Codegen.cpp +++ b/compiler/src/Codegen.cpp @@ -570,7 +570,8 @@ namespace { if (!compile_expr(f, value, tmp, func_of_name(sym.type_name))) { return false; } - E_slot(f, "STORE", tmp, git->second); + const size_t st = E_slot(f, "STORE", tmp, git->second); + set_func(f.code.data() + st, func_of_global(target)); return true; } diff --git a/tests/cases/21_var_temp/EXPECTED.md b/tests/cases/21_var_temp/EXPECTED.md new file mode 100644 index 0000000..600057e --- /dev/null +++ b/tests/cases/21_var_temp/EXPECTED.md @@ -0,0 +1,8 @@ +# 期望:编译通过;VAR_TEMP 每周期重置,VAR 跨周期持久 + +- FB Foo:`tmp`(VAR_TEMP 初值 100)每周期重置 → `tmp := tmp + 1` 恒为 101; + `persist`(VAR)跨周期累积 1、2、3… + `out = tmp * 100 + persist` = 10101、10102、10103… +- MAIN:`t`(VAR_TEMP 初值 5)每周期重置 → `t := t + 1` 恒为 6 +- 全局 `a = f.out + t`:周期 1/2/3 = 10107 / 10108 / 10109(差 1 仅来自 persist, + tmp 与 t 若不重置则偏差 100 / 1) diff --git a/tests/cases/21_var_temp/globals.st b/tests/cases/21_var_temp/globals.st new file mode 100644 index 0000000..1b42e52 --- /dev/null +++ b/tests/cases/21_var_temp/globals.st @@ -0,0 +1,4 @@ +(* globals.st *) +VAR_GLOBAL + a : INT; +END_VAR diff --git a/tests/cases/21_var_temp/main.st b/tests/cases/21_var_temp/main.st new file mode 100644 index 0000000..3147e21 --- /dev/null +++ b/tests/cases/21_var_temp/main.st @@ -0,0 +1,12 @@ +(* main.st *) +PROGRAM MAIN +VAR + f : Foo; +END_VAR +VAR_TEMP + t : INT := 5; +END_VAR + t := t + 1; + f(in := TRUE); + a := f.out + t; +END_PROGRAM diff --git a/tests/cases/21_var_temp/motor.st b/tests/cases/21_var_temp/motor.st new file mode 100644 index 0000000..b9dc507 --- /dev/null +++ b/tests/cases/21_var_temp/motor.st @@ -0,0 +1,18 @@ +(* motor.st *) +FUNCTION_BLOCK Foo +VAR_INPUT + in : BOOL; +END_VAR +VAR_OUTPUT + out : INT; +END_VAR +VAR + persist : INT; +END_VAR +VAR_TEMP + tmp : INT := 100; +END_VAR + tmp := tmp + 1; + persist := persist + 1; + out := tmp * 100 + persist; +END_FUNCTION_BLOCK diff --git a/tests/cases/21_var_temp/project.toml b/tests/cases/21_var_temp/project.toml new file mode 100644 index 0000000..e15d249 --- /dev/null +++ b/tests/cases/21_var_temp/project.toml @@ -0,0 +1,11 @@ +[project] +name = "case21" +entry = "program MAIN" +cycle_limit = 1000 +dt_ms = 10 + +[files] +st = ["globals.st", "motor.st", "main.st"] + +[gvl] +file = "globals.st" diff --git a/tests/src/cases_test.cpp b/tests/src/cases_test.cpp index 02b140c..2dd9956 100644 --- a/tests/src/cases_test.cpp +++ b/tests/src/cases_test.cpp @@ -65,6 +65,7 @@ namespace { {"18_tof_ctu", Outcome::Ok, ""}, {"19_recursive_call", Outcome::CompileError, "recursive call"}, {"20_line1", Outcome::Ok, ""}, + {"21_var_temp", Outcome::Ok, ""}, }; bool run_case(const char* dir, Outcome want, const char* keyword) { diff --git a/tests/src/compiler_test.cpp b/tests/src/compiler_test.cpp index d77fcb0..337f51a 100644 --- a/tests/src/compiler_test.cpp +++ b/tests/src/compiler_test.cpp @@ -202,7 +202,7 @@ static bool test_all_cases() { } ++n; } - CHECK(n == 20); + CHECK(n == 21); return true; } diff --git a/tests/src/vm_test.cpp b/tests/src/vm_test.cpp index ede2859..019f9d4 100644 --- a/tests/src/vm_test.cpp +++ b/tests/src/vm_test.cpp @@ -37,11 +37,19 @@ static int g_checks = 0; // ---- 数据区槽访问 ---- -/// 槽宽 = 与下一槽 addr 的差(紧凑布局下按实际宽读写,避免覆盖相邻槽)。 +/// 槽宽 = 与下一槽 addr 的差(紧凑布局下按实际宽读写,避免覆盖相邻槽); +/// 最后一槽(下一槽越界返回 0)按值区剩余字节兜底。 static uint32_t slot_width(const vm::Machine& m, int s) { const uint32_t a = m.slot_addr(static_cast(s)); const uint32_t b = m.slot_addr(static_cast(s + 1)); - return (b > a && b - a < 8) ? (b - a) : 8; + if (b > a && b - a < 8) { + return b - a; + } + if (b == 0) { + const uint32_t rem = static_cast(m.data_len()) - a; + return rem < 8 ? rem : 8; + } + return 8; } static int64_t slot(const vm::Machine& m, int s) { @@ -357,6 +365,15 @@ static bool test_cases_positive() { CHECK(make_machine("tests/cases/18_tof_ctu", &m, &err)); CHECK(m.run_cycle() == vm::Fault::None); + // 21 VAR_TEMP:tmp/t 每周期重置,persist 累积 → a = 10107/10108/10109 + CHECK(make_machine("tests/cases/21_var_temp", &m, &err)); + m.run_cycle(); + CHECK(slot(m, 0) == 10107); + m.run_cycle(); + CHECK(slot(m, 0) == 10108); + CHECK(m.run_cycle() == vm::Fault::None); + CHECK(slot(m, 0) == 10109); + // 20 line1:I 组合 → Q0_0 真值表(槽 0=急停 1=I0_0 2=I0_1 3=Q0_0) CHECK(make_machine("tests/cases/20_line1", &m, &err)); struct {