5.7 KiB
STCompiler 使用说明
把 ST 工程(project.toml + 若干 .st)编译成单一映像 .stb。执行由 BytecodeExecutor(12.9/12.10 实现)负责。
构建
cmake --preset gcc-debug # 配置
cmake --build --preset gcc-debug # 编译
ctest --test-dir build/gcc-debug # 测试(当前 9 个用例)
可执行文件:build/gcc-debug/compiler/STCompiler
用法
STCompiler <project.toml> [-o <name>.stb]
STCompiler <name>.stb --disasm
| 参数 | 作用 |
|---|---|
<project.toml> |
工程文件(必填) |
-o <name>.stb |
编译并写出映像文件;缺省时只打印文件集合与工程哈希(12.3 阶段行为) |
<name>.stb --disasm |
反汇编一个已编译的映像(不重新编译,见下) |
--help |
打印帮助 |
退出码:0 成功;1 编译失败(错误信息打到 stderr)。
反汇编(--disasm)
对已编译的 .stb 逐段查看:段摘要、函数表逐条指令(文件绝对偏移)、常量表、数据段 hex。
$ STCompiler line1.stb --disasm
image: line1.stb (184 bytes, 2 functions, 4 globals, entry fn 1)
dt_ms=10 cycle_limit=100000 hash=0xc3fe4ae74ad45900
functions:
fn 0: nregs=8, offset=0, len=1
0x0060 RET
fn 1: nregs=13, offset=4, len=17
0x0064 LOAD_I r8, 1
0x0068 STORE_GLOBAL r8, 8
0x006c LOAD_GLOBAL r9, 2
...
data (16 bytes):
0x0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
说明:
- 指令偏移是文件绝对字节偏移,可直接对照
xxd line1.stb - 映像里没有符号名(函数表只有 fn_id,数据段无名字映射),因此按
fn 0/fn 1、槽号显示 - 文件损坏或打不开 →
error: ...退出码 1
示例(line1)
$ STCompiler examples/line1/project.toml
project: line1
files:
globals.st
motor.st
main.st
hash: 0xc3fe4ae74ad45900
$ STCompiler examples/line1/project.toml -o line1.stb
compiled: line1.stb (184 bytes, 2 functions, 4 globals)
产物 line1.stb:魔数 STSC + 版本 1 的单一映像(指令见 Doc/isa/指令与映像.md)。
工程文件(project.toml)
只做三件事:列出源文件、指定唯一 GVL、可选地把已声明全局接到硬件。不声明变量。
| 字段 | 必填 | 说明 |
|---|---|---|
project.name |
是 | 工程名 |
project.entry |
是 | 第一版必须 "program MAIN" |
project.cycle_limit |
是 | 每周期指令上限(>0) |
project.dt_ms |
是 | 本周期 Δt 毫秒(>0),给 TON/TOF/CTU |
files.st |
是 | 源文件列表(非空数组) |
gvl.file |
否 | 唯一允许 VAR_GLOBAL 的文件;已在 files.st 则不重复收录 |
[[io.input]] / [[io.output]] |
否 | var + channel + bit;var 必须已在 GVL 声明 |
[project]
name = "line1"
entry = "program MAIN"
cycle_limit = 100000
dt_ms = 10
[files]
st = ["globals.st", "motor.st", "main.st"]
[gvl]
file = "globals.st"
[[io.input]]
var = "EmergencyStop"
channel = 0
bit = 2
ST 子集(第一版)
POU:PROGRAM / FUNCTION / FUNCTION_BLOCK(含对应 END_*)。
变量段:VAR / VAR_INPUT / VAR_OUTPUT / VAR_GLOBAL(仅 gvl.file 顶层)/ VAR_EXTERNAL。
类型:BOOL / INT / TIME;内建 FB 类型 TON / TOF / CTU(关键字,不可作变量名)。
语句:赋值 :=、IF / ELSIF / ELSE / END_IF、WHILE / END_WHILE、FB 调用 fb(in := ..., ...);、字段读 fb.Q。
表达式:字面量(TRUE/FALSE、整数、T#10ms 式 TIME)、NOT、AND/OR(短路)、比较 = <> < <= > >=(不连锁)、算术 + - * /、一元负号、函数调用 Add(3, 4)。
函数:结果 = 函数名赋值(Add := a + b;);返回类型 FUNCTION Add : INT;调用约定:结果 r0、参数 r1..r7(最多 7 个输入,函数内只读)、变量与临时从 r8 起(见 Doc/compiler/寄存器码.md)。
限制(v1 明确不做):指针 / REF / CLASS / ANY / VAR_IN_OUT(语法层直接拒绝)、链式比较、FB 字段赋值、REAL、字符串、用户类型套娃、隐式类型转换、函数循环调用(链接层拒绝)、FUNCTION 写全局(类型检查层拒绝,含经 VAR_EXTERNAL)。
编译管线与错误类别
project.toml + .st
→ 词法(lex error)→ 语法(syntax error)→ 链接(link error)
→ 类型检查(type error)→ 寄存器码(codegen error)→ .stb
错误消息前缀即阶段:lex error / syntax error / link error / type error / codegen error,均带文件与行列(type error 仅带文件)。
| 类别 | 示例 |
|---|---|
lex error |
非法字符、未闭合注释、坏 T# 字面量 |
syntax error |
缺 END_*、VAR_IN_OUT 等保留名、链式比较 |
link error |
非 GVL 文件写 VAR_GLOBAL、同名全局、io.var 未在 GVL、未声明实例、循环调用 |
type error |
FUNCTION 写全局、AND 吃 INT、赋值类型不匹配、FB 输入类型不匹配 |
codegen error |
寄存器溢出、写 io.input、写函数输入 |
样例与测试
examples/line1/:最小闭环(MAIN + MotorStarter FB + I/O + 全局),给人看tests/cases/01~20/:20 个用例(每份project.toml+.st+EXPECTED.md),编译结果按表tests/:CTest(isa_roundtrip/compiler_toml/lexer_tokens/parser_syntax/linker_links/typecheck_types/codegen_slice1)
当前状态
- ✅ 可编译:14 个正例用例全部产出
.stb;6 个负例按期望拒绝 - ⏳ 执行:
BytecodeExecutor(加载.stb跑扫描周期)在 12.9/12.10 - ⏳ sidecar(
<name>.runtime.toml,I/O 绑定)在 12.10 随执行器一起接线