moonplc

    IEC 61131-3 Soft PLC Runtime and Structured Text Engine in MoonBit

    plc
    iec61131-3
    runtime
    structured-text
    ladder-logic
    simulator
    wasm
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    14 hours ago
    Downloads
    2

    #MoonPLC: 软 PLC 运行时与 IEC 61131-3 子集编译器

    CI License MoonBit Hackathon

    MoonPLC 是专为 2026 MoonBit 黑客松 设计的工业软件基础设施项目:采用 100% 纯 MoonBit 实现的轻量级微型软 PLC 运行时(Soft PLC Runtime)与 IEC 61131-3 工业标准编程语言(结构化文本 ST + 梯形图 LD)编译器,配备毫秒级确定性周期扫描引擎与浏览器端 WebAssembly 工业数字孪生仿真工作台。


    #项目目标 (Project Objectives)

    1. 破局工业软件垄断,探索下一代自主工控语言基础设施: 传统软 PLC(如西门子 S7、德国 CODESYS、倍福 TwinCAT)长期闭源且收费高昂,开源项目(如 OpenPLC/MATIEC)技术栈老旧且存在 C 语言固有的内存安全缺陷。MoonPLC 旨在利用 MoonBit 的强静态类型、内存安全与极速编译特性,探索现代高可靠语言在 OT(运营技术)与工业边缘计算控制系统中的应用。
    2. 轻量化 IEC 61131-3 工业语言子集编译器: 提供标准结构化文本(Structured Text, ST)与梯形图(Ladder Diagram, LD)的词法、语法解析与 AST 编译能力,支持将工业梯级布尔网络与复杂控制流转化为统一可执行中间表示。
    3. 确定性毫秒级扫描周期执行引擎 (Scan Cycle Engine): 严格还原工业控制器的核心调度机制——“输入采样 (Input Scan) -> 逻辑执行 (Program Execution) -> 输出刷新 (Output Scan)”,内置看门狗 (Watchdog) 与时基调度器。
    4. 全平台仿真与教学实验环境: 高校与工程师无需安装数十 GB 的庞大工业软件,即可在 PC 终端(Native CLI)或现代浏览器(WebAssembly)中以微秒/毫秒时钟精确仿真一台虚拟 PLC,并观察发光 I/O 指示灯、动态高亮梯形图及电机/交通灯物理动效。


    #安装方式 (Installation)

    #1. 前置依赖准备

    确保本地安装有 Git 以及最新版的 MoonBit 工具链:

    • 安装 MoonBit 工具链 (Linux / macOS):
      curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash
    • 安装 MoonBit 工具链 (Windows PowerShell):
      irm https://cli.moonbitlang.com/install/powershell.ps1 | iex
    • 验证安装:
      moon version # 推荐版本 >= 0.1.20260915

    #2. 获取源码与编译构建

    # 克隆仓库 git clone https://github.com/lycvvt/Moonplc.git cd Moonplc # 执行静态检查与依赖加载 moon check # 编译项目与测试套件 moon test

    #3. 作为依赖引入到您的 MoonBit 工程

    在您工程的 moon.mod 中添加依赖引用:
    import {
    "lycvvt/moonplc"
    }


    #使用方法 (Usage Guide)

    #1. 命令行 CLI 交互仿真

    项目内置了丰富的工业控制仿真示例程序,可直接通过 moon run 启动:
    moon run cmd/main
    终端将输出工业控制界面,并按周期时序连续执行:
    • 电机启保停自锁控制(按钮输入、自锁锁存、停止复位全过程)。
    • 十字路口交通信号灯定时器延时翻转全过程。
    • 水箱闭环 PID 温度调节控制。
    • Modbus 现场总线数据读写通信。

    #2. 浏览器端 Web 工业数字孪生工作台 (MoonPLC Studio)

    无需搭建后端或复杂服务,直接在浏览器中打开前端界面:
    • 方式 A(直接双击):用任何现代浏览器(Chrome、Edge、Firefox、Safari)双击打开 web/index.html。
    • 方式 B(本地 HTTP 服务):
      # 使用任意轻量 HTTP 伺服 npx serve web # 或使用 python python -m http.server 8080 --directory web
    • 打开后即可进入 SCADA 工业控制台:
      • 点击左侧下拉菜单切换案例(电机控制、智能交通灯、流水线推杆)。
      • 点击中间面板的 %IX0.0 模拟物理开关按下。
      • 实时观察梯形图发光导通回路、I/O 机架 LED 灯以及右侧电机旋转/红绿灯交替动效。

    #3. MoonBit 代码中调用 MoonPLC API

    在 MoonBit 代码中引入并驱动软 PLC 运行时:

    import "lycvvt/moonplc" as plc

    fn main {
    // 1. 实例化一个软 PLC 控制器
    let controller = plc.MoonPlc::new("IndustrialUnit_01")

    // 2. 加载 IEC 61131-3 结构化文本 (ST) 程序
    let st_program =
    #|PROGRAM ConveyorControl
    #|VAR
    #| Sensor_Item AT %IX0.0 : BOOL;
    #| Piston_Push AT %QX0.0 : BOOL;
    #|END_VAR
    #|IF Sensor_Item THEN
    #| Piston_Push := TRUE;
    #|ELSE
    #| Piston_Push := FALSE;
    #|END_IF;
    #|END_PROGRAM
    controller.load_st(st_program)

    // 3. 模拟外部传感器信号输入 (%IX0.0 置为 TRUE)
    controller.set_input_bool("%IX0.0", true)

    // 4. 执行一个 10ms 扫描周期
    controller.cycle(10L)

    // 5. 读取物理输出映像寄存器状态
    let is_piston_active = controller.get_output_bool("%QX0.0")
    println("Piston state: \{is_piston_active}") // true

    // 6. 打印 PLC 内部完整 I/O 状态表与时基统计
    println(controller.dump_status())
    }


    #典型工业应用示例 (Examples)

    所有示例源码均保存在 examples/ 目录中:

    #示例 1: 电机自锁启保停控制 (Motor Start-Stop Self-Hold)

    • 源码文件:examples/01_motor_start_stop.st
    • 控制逻辑:
      Motor_Run := (Start_Btn OR Motor_Run) AND NOT Stop_Btn;
    • 核心特点:展示经典的梯形图常开触点、并联自锁回路与常闭停止触点互锁,断开启动按钮后依然能通过线圈自身触点维持接通。

    #示例 2: 道路十字路口智能交通信号灯 (Traffic Light Sequence)

    • 源码文件:examples/02_traffic_light.st
    • 控制逻辑:
      IF Car_Present OR Pedestrian THEN Light_Red := FALSE; Light_Green := TRUE; Timer_Pass(IN := TRUE, PT := T#3s); IF Timer_Pass.Q THEN Light_Green := FALSE; Light_Amber := TRUE; END_IF; ELSE Light_Red := TRUE; Light_Green := FALSE; Light_Amber := FALSE; END_IF;
    • 核心特点:结合工业级标准 TON(通电延时定时器),模拟车辆/行人触发后的毫秒级确定性时序转换。

    #示例 3: 自动化流水线物料感应与气缸分拣 (Conveyor Belt Sorting)

    • 源码文件:examples/03_conveyor_sorting.st
    • 核心特点:利用 TP(脉冲定时器)在物料触发光电传感器的瞬间输出固定宽度的气缸推杆动作,实现精准分拣与计数。

    #示例 4: 水箱恒温闭环 PID 控制系统 (Closed-Loop PID Tank)

    #示例 5: 梯形图 JSON 交换规范

    • 源码文件:examples/04_ladder_demo.json
    • 核心特点:提供规范化的抽象语法梯级 JSON 定义,支持与现代 Web 前端、组态软件及工业 SCADA 系统双向数据交换。


    #完整可复现的验证步骤 (Reproducibility)

    为了让大赛评委和开源社区开发者能够 100% 精确复现本项目的运行与测试结果,请依照以下步骤验证:

    #步骤 1: 代码规范与静态检查验证

    moon fmt --check || moon fmt moon check
    • 预期结果:控制台输出 Finished. moon: ran tasks, now up to date,实现 0 编译警告、0 语法错误。

    #步骤 2: 全套自动化测试执行

    moon test
    • 预期结果:
      Total tests: 41, passed: 41, failed: 0.
      涵盖:数据类型编解码测试、ST 词法与语法分析测试、梯形图自锁电路编译测试、过程映像内存映射测试、TON/TOF/TP/TONR/CTU/CTUD 功能块测试、SR/RS 触发器、R_TRIG/F_TRIG 边沿检测、工业闭环 PID 控制器测试、Modbus TCP/RTU 现场总线协议编解码与 CRC16 校验测试、ST-to-IL 字节码编译器与 IL 虚拟机单步与跳转测试、以及 50,000 周期高频扫描基准压力测试,全量 41 项 100% 绿色通过。

    #步骤 3: 终端工业仿真 CLI 运行复现

    moon run cmd/main
    • 预期输出:
      ================================================================ IEC 61131-3 Soft PLC Runtime & Structured Text Simulator Pure MoonBit Implementation | WebAssembly & Edge Ready ================================================================ [SCENARIO 1] Ladder Diagram: Motor Start-Stop Self-Hold Circuit >> Step 1: Initial state -> Motor_Run = FALSE >> Step 2: Press [START] Button -> Motor_Run = TRUE [MOTOR STARTED] >> Step 3: Release [START] Button -> Motor_Run = TRUE [SELF-LATCH MAINTAINED] >> Step 4: Press [STOP] Button -> Motor_Run = FALSE [MOTOR STOPPED] [SCENARIO 2] Structured Text: Traffic Light Timing Control >> Car Arrives! Triggering %IX0.0 = TRUE [At 50ms] RED = false | GREEN = true | AMBER = false [At 110ms] RED = false | GREEN = false | AMBER = true [SCENARIO 3] Process Automation: Closed-Loop PID Temperature Control >> Target Setpoint: 65.0°C | Initial Tank Temperature: 25.0°C Step 1 | Heater Output = 81% | Tank Temp = 31°C Step 2 | Heater Output = 98% | Tank Temp = 39°C Step 3 | Heater Output = 85% | Tank Temp = 45°C Step 4 | Heater Output = 76% | Tank Temp = 51°C Step 5 | Heater Output = 67% | Tank Temp = 56°C [SCENARIO 4] Fieldbus: Modbus TCP/RTU Protocol Telemetry >> SCADA Host writes Coil 0 (%QX0.0) via Modbus FC 0x05 Response Error: false | %QX0.0 Status = true >> SCADA Host writes Holding Register 40001 (%MW0) = 8848 via Modbus FC 0x06 Response Error: false | Written Value = 8848

    #步骤 4: Web 端数字孪生交互复现

    1. 双击打开 web/index.html。
    2. 观察顶部状态栏显示 PLC RUNNING,周期计数器以 20ms 间隔平稳递增。
    3. 点击 %IX0.0 [启动/传感器]:
      • 梯形图上的 Start_Btn 触点即刻变绿发光。
      • Motor_Run 线圈接通,右侧三相交流电机开始高速旋转(2800 RPM 动效)。
    4. 再次点击 %IX0.0 取消按钮输入:电机依靠自锁常开触点维持平稳运转。
    5. 点击 %IX0.1 [停止]:电机即刻刹车停止,完全吻合工业现场电气控制行为。


    #系统架构图 (Architecture)

    graph TD subgraph Frontend["编译前端 (IEC 61131-3 Frontend)"] ST[ST 结构化文本源码] --> Lexer[词法分析器 Lexer] Lexer --> Parser[递归下降语法解析器 Parser] LD[梯形图 LD 梯级数据] --> LDTrans[布尔代数转换器 LadderCompiler] Parser --> AST[AST 抽象语法树] LDTrans --> AST end subgraph Core["运行时与执行引擎 (MoonPLC Core)"] AST --> Executor[AST 控制流与表达式求值] FB[标准功能块库 TON/TOF/TP/CTU] <--> Executor PID[工业闭环 PID 控制器] <--> Executor MB[Modbus 通信协议栈] <--> Scheduler IL[IL 字节码虚拟机] <--> Executor subgraph Scheduler["周期调度器 (Scan Scheduler)"] P1[1. 输入采样 Input Scan] --> P2[2. 逻辑执行 Execution] P2 --> P3[3. 输出刷新 Output Scan] end Mem[(过程映像存储区 Memory)] <--> Scheduler Executor <--> Mem end subgraph Target["外设与仿真 (Simulation & Targets)"] Scheduler --> CLI[CLI 命令行测试器] Scheduler --> WebUI[WebAssembly 工业数字孪生工作台] end


    #项目工程目录 (Repository Structure)

    Moonplc/ ├── moon.mod # MoonBit 模块定义 ├── moon.pkg # 核心库包配置 (零告警选项) ├── pkg.generated.mbti # 自动生成的标准公共接口定义 ├── types.mbt # IEC 基础类型与 %IX 寻址表示 ├── types_wbtest.mbt # 类型白盒单测 ├── ast.mbt # ST 抽象语法树 ├── lexer.mbt # 词法分析器 ├── lexer_wbtest.mbt # 词法分析白盒单测 ├── parser.mbt # 递归下降语法解析器 ├── parser_wbtest.mbt # 语法解析白盒单测 ├── ladder.mbt # 梯形图数据结构与转 AST 引擎 ├── ladder_wbtest.mbt # 梯形图白盒单测 ├── memory.mbt # 过程映像区与变量符号表 ├── memory_wbtest.mbt # 内存映像白盒单测 ├── fblocks.mbt # 工业标准功能块 (TON/TOF/TP/CTU/SR/RS/R_TRIG/F_TRIG) ├── fblocks_wbtest.mbt # 功能块白盒单测 ├── pid.mbt # 工业闭环 PID 控制器 (抗饱和/微分先行) ├── pid_wbtest.mbt # PID 闭环恒温仿真测试 ├── modbus.mbt # 现场总线 Modbus TCP 协议编解码与寄存器映射 ├── modbus_wbtest.mbt # Modbus TCP 协议白盒单测 ├── modbus_rtu.mbt # Modbus RTU 物理帧编解码与 CRC16 校验 ├── modbus_rtu_wbtest.mbt # Modbus RTU 报文与校验白盒单测 ├── compiler.mbt # ST 到 IL 字节码编译器 (表达式/控制流) ├── compiler_wbtest.mbt # 编译器与虚拟机联调白盒单测 ├── vm.mbt # IEC 61131-3 指令表 (IL) 字节码虚拟机 ├── vm_wbtest.mbt # IL 虚拟机白盒单测 ├── runtime.mbt # 周期调度引擎与解释执行器 ├── runtime_wbtest.mbt # 周期扫描集成白盒测试 ├── bench_wbtest.mbt # 50,000 周期高频扫描与总线基准压测套件 ├── moonplc.mbt # 统一 Facade API ├── moonplc_wbtest.mbt # 端到端工作流白盒测试 ├── cmd/ │ └── main/ │ ├── main.mbt # CLI 命令行仿真程序 (四大场景) │ ├── moon.pkg │ └── pkg.generated.mbti ├── web/ │ └── index.html # 浏览器 SCADA 工业仿真控制台 ├── examples/ # 典型工业案例 (电机、红绿灯、流水线、恒温水箱) ├── docs/ │ └── ACCEPTANCE.md # 黑客松结项验收自查报告 ├── PROPOSAL.md # 大赛项目申报说明书 ├── .github/workflows/ci.yml # GitHub Actions CI └── LICENSE # Apache-2.0


    #赛事信息与评审致谢

    • 参赛项目:MoonPLC —— 软 PLC 运行时与 IEC 61131-3 子集编译器
    • 参赛选手:@lycvvt
    • 主办单位:中国计算机学会 (CCF)、粤港澳大湾区数字经济研究院 (IDEA Research)
    • 项目申报说明:详见 PROPOSAL.md


    #开源许可证 (License)

    本项目基于 Apache-2.0 License 开源。

    BinaryOp

    pub(all) enum BinaryOp {
    Add
    Sub
    Mul
    Div
    Mod
    Eq
    Neq
    Lt
    Lte
    Gt
    Gte
    And
    Or
    Xor
    } derive(Eq,
    Debug
    )

    二元运算符

    Coil

    pub(all) enum Coil {
    Normal(String)
    Set(String)
    Reset(String)
    DirectCoil(PlcAddress)
    } derive(Eq,
    Debug
    )

    输出线圈类型

    Contact

    pub(all) enum Contact {
    NormallyOpen(String)
    NormallyClosed(String)
    DirectNO(PlcAddress)
    DirectNC(PlcAddress)
    RisingEdgeContact(String)
    FallingEdgeContact(String)
    CompareContact(String, BinaryOp, Int)
    } derive(Eq,
    Debug
    )

    触点类型

    CtuCounter

    pub(all) struct CtuCounter {
    cu_prev : Bool
    pv : Int
    cv : Int
    q : Bool
    } derive(
    Debug
    )

    CTU: 增计数器 (Count Up)

    CtuCounter::new

    fn CtuCounter::new() -> CtuCounter

    CtuCounter::tick

    fn CtuCounter::tick(self : CtuCounter, cu_val : Bool, reset_val : Bool, pv_val : Int) -> Unit

    CTU 步进计算

    CtudCounter

    pub(all) struct CtudCounter {
    cu_prev : Bool
    cd_prev : Bool
    pv : Int
    cv : Int
    qu : Bool
    qd : Bool
    } derive(
    Debug
    )

    CTUD: 增减双向计数器 (Count Up/Down)

    CtudCounter::new

    CtudCounter::tick

    fn CtudCounter::tick(self : CtudCounter, cu_val : Bool, cd_val : Bool, r_val : Bool, ld_val : Bool, pv_val : Int) -> Unit

    Expr

    pub(all) enum Expr {
    Literal(PlcValue)
    Variable(String)
    DirectAddress(PlcAddress)
    Binary(Expr, BinaryOp, Expr)
    Unary(UnaryOp, Expr)
    FieldAccess(String, String)
    } derive(
    Debug
    )

    ST 表达式

    FTrig

    pub(all) struct FTrig {
    clk_prev : Bool
    q : Bool
    } derive(
    Debug
    )

    F_TRIG: 下降沿检测触发器 (Falling Edge Detector)

    FTrig::new

    fn FTrig::new() -> FTrig

    FTrig::tick

    fn FTrig::tick(self : FTrig, clk_val : Bool) -> Bool

    FbInstance

    pub(all) enum FbInstance {
    Ton(TonTimer)
    Tof(TofTimer)
    Tp(TpTimer)
    Tonr(TonrTimer)
    Ctu(CtuCounter)
    Ctud(CtudCounter)
    Sr(SrFlipFlop)
    Rs(RsFlipFlop)
    Rtrig(RTrig)
    Ftrig(FTrig)
    } derive(
    Debug
    )

    通用功能块实例封装

    FbInstance::get_field

    fn FbInstance::get_field(self : FbInstance, field : String) -> PlcValue

    获取功能块内部字段值 (如 Timer1.Q 或 Counter1.CV)

    IlInstruction

    pub(all) struct IlInstruction {
    opcode : IlOpcode
    operand_val : PlcValue?
    operand_var : String?
    } derive(
    Debug
    )

    单条 IL 虚拟机指令

    IlInstruction::new

    IlInstruction::with_val

    fn IlInstruction::with_val(op : IlOpcode, val : PlcValue) -> IlInstruction

    IlInstruction::with_var

    fn IlInstruction::with_var(op : IlOpcode, var_name : String) -> IlInstruction

    IlOpcode

    pub(all) enum IlOpcode {
    Ld
    Ldn
    St
    And
    Andn
    Or
    Orn
    Xor
    Add
    Sub
    Mul
    Div
    Mod
    Eq
    Ne
    Gt
    Lt
    Ge
    Le
    Jmp(Int)
    Jmpc(Int)
    Jmpcn(Int)
    Halt
    } derive(Eq,
    Debug
    )

    IL 指令操作码定义

    LadderDiagram

    pub(all) struct LadderDiagram {
    name : String
    rungs : Array[Rung]
    } derive(
    Debug
    )

    完整梯形图程序

    LadderDiagram::add_rung

    fn LadderDiagram::add_rung(self : LadderDiagram, rung : Rung) -> Unit

    添加梯级

    LadderDiagram::new

    fn LadderDiagram::new(name : String) -> LadderDiagram

    创建梯形图

    LadderDiagram::to_program

    fn LadderDiagram::to_program(self : LadderDiagram) -> Program

    将整套梯形图编译为 ST 抽象语法树 (Program)

    LadderNode

    pub(all) enum LadderNode {
    Leaf(Contact)
    Series(Array[LadderNode])
    Parallel(Array[LadderNode])
    } derive(Eq,
    Debug
    )

    梯形图逻辑节点 (支持任意深度的串并联布尔网络)

    Lexer

    pub(all) struct Lexer {
    chars : Array[Char]
    len : Int
    pos : Int
    } derive(
    Debug
    )

    词法分析器状态

    Lexer::new

    fn Lexer::new(src : String) -> Lexer

    创建 Lexer

    Lexer::next_token

    fn Lexer::next_token(self : Lexer) -> Token

    读取下一个 Token

    Lexer::tokenize

    fn Lexer::tokenize(self : Lexer) -> Array[Token]

    解析全部 Token 到数组

    ModbusException

    pub(all) enum ModbusException {
    IllegalFunction
    IllegalDataAddress
    IllegalDataValue
    SlaveDeviceFailure
    } derive(Eq,
    Debug
    )

    Modbus 异常码 (Exception Codes)

    ModbusFunction

    pub(all) enum ModbusFunction {
    ReadCoils
    ReadDiscreteInputs
    ReadHoldingRegisters
    ReadInputRegisters
    WriteSingleCoil
    WriteSingleRegister
    WriteMultipleRegisters
    Unknown(Int)
    } derive(Eq,
    Debug
    )

    Modbus 标准功能码定义

    ModbusFunction::from_int

    fn ModbusFunction::from_int(code : Int) -> ModbusFunction

    ModbusFunction::to_int

    fn ModbusFunction::to_int(self : ModbusFunction) -> Int

    ModbusRequest

    pub(all) struct ModbusRequest {
    slave_id : Int
    function_code : ModbusFunction
    address : Int
    quantity : Int
    values : Array[Int]
    } derive(
    Debug
    )

    Modbus 请求数据包 (PDU - Protocol Data Unit)

    ModbusRequest::new

    fn ModbusRequest::new(slave_id : Int, fc : ModbusFunction, address : Int, quantity : Int) -> ModbusRequest

    ModbusResponse

    pub(all) struct ModbusResponse {
    slave_id : Int
    function_code : ModbusFunction
    is_error : Bool
    exception_code : ModbusException?
    byte_count : Int
    data : Array[Int]
    } derive(
    Debug
    )

    Modbus 响应数据包

    MoonPlc

    pub(all) struct MoonPlc {
    runtime : PlcRuntime
    name : String
    } derive(
    Debug
    )

    微型软 PLC 控制器实例

    MoonPlc::current_time_ms

    fn MoonPlc::current_time_ms(self : MoonPlc) -> Int64

    获取仿真当前时间 (ms)

    MoonPlc::cycle

    fn MoonPlc::cycle(self : MoonPlc, delta_ms : Int64) -> Unit

    执行单个扫描周期 (毫秒步进)

    MoonPlc::cycle_count

    fn MoonPlc::cycle_count(self : MoonPlc) -> Int64

    获取当前累计周期数

    MoonPlc::dump_status

    fn MoonPlc::dump_status(self : MoonPlc) -> String

    打印控制器当前状态与 I/O 摘要

    MoonPlc::get_output_bool

    fn MoonPlc::get_output_bool(self : MoonPlc, addr : String) -> Bool

    读取物理数字输出点 (例如 "%QX0.0")

    MoonPlc::get_var

    fn MoonPlc::get_var(self : MoonPlc, name : String) -> PlcValue

    读取内部或命名变量

    MoonPlc::load_ladder

    fn MoonPlc::load_ladder(self : MoonPlc, ld : LadderDiagram) -> Unit

    从梯形图 (LD) 对象加载程序

    MoonPlc::load_st

    fn MoonPlc::load_st(self : MoonPlc, source : String) -> Unit

    从 IEC 61131-3 结构化文本 (ST) 源代码加载程序

    MoonPlc::new

    fn MoonPlc::new(name : String) -> MoonPlc

    创建新 PLC 实例

    MoonPlc::run_cycles

    fn MoonPlc::run_cycles(self : MoonPlc, count : Int, delta_ms : Int64) -> Unit

    批量运行多个扫描周期

    MoonPlc::set_input_bool

    fn MoonPlc::set_input_bool(self : MoonPlc, addr : String, val : Bool) -> Unit

    设置物理数字输入点 (例如 "%IX0.0", true)

    MoonPlc::set_var

    fn MoonPlc::set_var(self : MoonPlc, name : String, val : PlcValue) -> Unit

    设置内部或命名变量

    Parser

    pub(all) struct Parser {
    tokens : Array[Token]
    len : Int
    pos : Int
    } derive(
    Debug
    )

    Parser 状态

    Parser::from_source

    fn Parser::from_source(src : String) -> Parser

    从源代码直接创建 Parser

    Parser::new

    fn Parser::new(tokens : Array[Token]) -> Parser

    创建 Parser

    Parser::parse_expr

    fn Parser::parse_expr(self : Parser) -> Expr

    表达式解析入口

    Parser::parse_program

    fn Parser::parse_program(self : Parser) -> Program

    解析完整 PROGRAM 程序

    Parser::parse_statement

    fn Parser::parse_statement(self : Parser) -> Stmt

    解析单个语句

    Parser::parse_statement_list

    fn Parser::parse_statement_list(self : Parser) -> Array[Stmt]

    解析语句列表 (直到遇到 END_*, ELSE, ELSIF, EOF)

    Parser::parse_var_block

    fn Parser::parse_var_block(self : Parser) -> Array[VarDecl]

    解析 VAR ... END_VAR 块

    Parser::peek_next

    fn Parser::peek_next(self : Parser) -> Token

    查看下一个 Token

    PidController

    pub(all) struct PidController {
    kp : Double
    ti_ms : Double
    td_ms : Double
    out_min : Double
    out_max : Double
    deadband : Double
    integral_acc : Double
    prev_pv : Double
    prev_error : Double
    manual : Bool
    manual_val : Double
    output : Double
    } derive(
    Debug
    )

    工业 PID 控制器结构

    PidController::compute

    fn PidController::compute(self : PidController, sp : Double, pv : Double, dt_ms : Double) -> Double

    PID 周期执行计算 (按采样周期 dt 毫秒计算输出)

    PidController::new

    fn PidController::new(kp : Double, ti_ms : Double, td_ms : Double) -> PidController

    创建默认工业 PID 控制器

    PidController::set_deadband

    fn PidController::set_deadband(self : PidController, db : Double) -> Unit

    设置误差死区

    PidController::set_limits

    fn PidController::set_limits(self : PidController, min_val : Double, max_val : Double) -> Unit

    设置输出限幅区间

    PidController::set_manual

    fn PidController::set_manual(self : PidController, manual_mode : Bool, man_val : Double) -> Unit

    手动/自动模式无扰切换 (Bumpless Transfer)

    PlcAddress

    pub(all) struct PlcAddress {
    area : PlcArea
    size : PlcDataSize
    byte_offset : Int
    bit_offset : Int
    } derive(Eq,
    Debug
    )

    PLC 统一地址定义 (例如 %IX0.0, %QX1.2, %MW10)

    PlcAddress::to_key

    fn PlcAddress::to_key(self : PlcAddress) -> String

    格式化 PlcAddress 为紧凑键值 (如 "%IX0.1")

    PlcArea

    pub(all) enum PlcArea {
    Input
    Output
    Memory
    } derive(Eq,
    Debug
    )

    PLC 物理/逻辑存储区

    PlcDataSize

    pub(all) enum PlcDataSize {
    Bit
    Byte
    Word
    DWord
    } derive(Eq,
    Debug
    )

    寻址大小

    PlcMemory

    pub(all) struct PlcMemory {
    inputs : Map[String, PlcValue]
    outputs : Map[String, PlcValue]
    flags : Map[String, PlcValue]
    vars : Map[String, PlcValue]
    var_bindings : Map[String, PlcAddress]
    } derive(
    Debug
    )

    PLC 存储区管理

    PlcMemory::bind_variable

    fn PlcMemory::bind_variable(self : PlcMemory, name : String, addr : PlcAddress) -> Unit

    绑定变量名到物理地址

    PlcMemory::dump_io

    fn PlcMemory::dump_io(self : PlcMemory) -> String

    打印当前 I/O 状态汇总

    PlcMemory::get_address_val

    fn PlcMemory::get_address_val(self : PlcMemory, addr : PlcAddress) -> PlcValue

    获取物理直接地址的值

    PlcMemory::get_output_bool

    fn PlcMemory::get_output_bool(self : PlcMemory, addr_str : String) -> Bool

    外部输出读取便捷方法 (驱动虚拟执行机构或仿真 UI)

    PlcMemory::get_var

    fn PlcMemory::get_var(self : PlcMemory, name : String) -> PlcValue

    获取变量值 (若绑定了物理地址,优先从物理映像区读取)

    PlcMemory::new

    fn PlcMemory::new() -> PlcMemory

    创建新存储区

    PlcMemory::reset

    fn PlcMemory::reset(self : PlcMemory) -> Unit

    重置所有存储区为初始 0 / FALSE

    PlcMemory::set_address_val

    fn PlcMemory::set_address_val(self : PlcMemory, addr : PlcAddress, val : PlcValue) -> Unit

    设置物理直接地址的值

    PlcMemory::set_input_bool

    fn PlcMemory::set_input_bool(self : PlcMemory, addr_str : String, val : Bool) -> Unit

    外部输入写入便捷方法 (模拟硬件传感器或外设触发)

    PlcMemory::set_var

    fn PlcMemory::set_var(self : PlcMemory, name : String, val : PlcValue) -> Unit

    设置变量值 (若绑定了物理地址,自动同步写入物理映像区)

    PlcModbusServer

    pub(all) struct PlcModbusServer {
    mem : PlcMemory
    slave_id : Int
    } derive(
    Debug
    )

    PLC Modbus 服务端适配器

    PlcModbusServer::handle_request

    fn PlcModbusServer::handle_request(self : PlcModbusServer, req : ModbusRequest) -> ModbusResponse

    处理 Modbus 请求并生成响应

    PlcModbusServer::new

    fn PlcModbusServer::new(mem : PlcMemory, slave_id : Int) -> PlcModbusServer

    PlcRuntime

    pub(all) struct PlcRuntime {
    mem : PlcMemory
    fb_instances : Map[String, FbInstance]
    program : Program?
    cycle_count : Int64
    current_time_ms : Int64
    scan_time_us : Int64
    watchdog_ms : Int64
    is_running : Bool
    } derive(
    Debug
    )

    运行时执行环境

    PlcRuntime::eval_expr

    fn PlcRuntime::eval_expr(self : PlcRuntime, expr : Expr) -> PlcValue

    计算表达式的值

    PlcRuntime::execute_statement

    fn PlcRuntime::execute_statement(self : PlcRuntime, stmt : Stmt, delta_ms : Int64) -> Unit

    执行单个语句

    PlcRuntime::execute_statement_list

    fn PlcRuntime::execute_statement_list(self : PlcRuntime, stmts : Array[Stmt], delta_ms : Int64) -> Unit

    执行语句序列

    PlcRuntime::load_program

    fn PlcRuntime::load_program(self : PlcRuntime, prog : Program) -> Unit

    加载程序 (POU) 并初始化变量

    PlcRuntime::new

    fn PlcRuntime::new() -> PlcRuntime

    创建 PLC 运行时

    PlcRuntime::step_cycle

    fn PlcRuntime::step_cycle(self : PlcRuntime, delta_ms : Int64) -> Unit

    执行一个完整的扫描周期 (Scan Cycle)

    PlcValue

    pub(all) enum PlcValue {
    Bool(Bool)
    Int(Int)
    Real(Double)
    Time(Int64)
    String(String)
    Null
    } derive(
    Debug
    )

    PlcValue::add

    fn PlcValue::add(self : PlcValue, other : PlcValue) -> PlcValue

    加法运算

    PlcValue::div

    fn PlcValue::div(self : PlcValue, other : PlcValue) -> PlcValue

    除法运算

    PlcValue::eq

    fn PlcValue::eq(self : PlcValue, other : PlcValue) -> Bool

    比较相等性

    PlcValue::is_true

    fn PlcValue::is_true(self : PlcValue) -> Bool

    PlcValue::lt

    fn PlcValue::lt(self : PlcValue, other : PlcValue) -> Bool

    比较大小 (<)

    PlcValue::lte

    fn PlcValue::lte(self : PlcValue, other : PlcValue) -> Bool

    比较大小 (<=)

    PlcValue::modulo

    fn PlcValue::modulo(self : PlcValue, other : PlcValue) -> PlcValue

    取模运算

    PlcValue::mul

    fn PlcValue::mul(self : PlcValue, other : PlcValue) -> PlcValue

    乘法运算

    PlcValue::sub

    fn PlcValue::sub(self : PlcValue, other : PlcValue) -> PlcValue

    减法运算

    PlcValue::to_double

    fn PlcValue::to_double(self : PlcValue) -> Double

    PlcValue::to_int

    fn PlcValue::to_int(self : PlcValue) -> Int

    PlcValue::to_string_repr

    fn PlcValue::to_string_repr(self : PlcValue) -> String

    PlcVm

    pub(all) struct PlcVm {
    instructions : Array[IlInstruction]
    mem : PlcMemory
    pc : Int
    acc : PlcValue
    halted : Bool
    } derive(
    Debug
    )

    虚拟机状态

    PlcVm::load_instructions

    fn PlcVm::load_instructions(self : PlcVm, instrs : Array[IlInstruction]) -> Unit

    PlcVm::new

    fn PlcVm::new(mem : PlcMemory) -> PlcVm

    PlcVm::reset

    fn PlcVm::reset(self : PlcVm) -> Unit

    重置虚拟机状态 (用于下一个扫描周期重新从头执行)

    PlcVm::run

    fn PlcVm::run(self : PlcVm, max_steps : Int) -> Unit

    连续执行指令序列直到停机或达到最大周期指令上限

    PlcVm::step

    fn PlcVm::step(self : PlcVm) -> Bool

    单步执行一条指令

    Program

    pub(all) struct Program {
    name : String
    variables : Array[VarDecl]
    statements : Array[Stmt]
    } derive(
    Debug
    )

    完整 ST 程序单元 (POU - Program Organization Unit)

    Program::new

    fn Program::new(name : String) -> Program

    创建空程序

    RTrig

    pub(all) struct RTrig {
    clk_prev : Bool
    q : Bool
    } derive(
    Debug
    )

    R_TRIG: 上升沿检测触发器 (Rising Edge Detector)

    RTrig::new

    fn RTrig::new() -> RTrig

    RTrig::tick

    fn RTrig::tick(self : RTrig, clk_val : Bool) -> Bool

    RsFlipFlop

    pub(all) struct RsFlipFlop {
    q1 : Bool
    } derive(
    Debug
    )

    RS: 复位优先双稳态触发器 (Reset-Dominant Bistable)

    RsFlipFlop::new

    fn RsFlipFlop::new() -> RsFlipFlop

    RsFlipFlop::tick

    fn RsFlipFlop::tick(self : RsFlipFlop, s_val : Bool, r1_val : Bool) -> Bool

    Rung

    pub(all) struct Rung {
    id : Int
    comment : String
    condition : LadderNode
    coils : Array[Coil]
    } derive(
    Debug
    )

    梯级 (Rung):从左母线流经触点逻辑网络,驱动末端线圈

    Rung::new

    fn Rung::new(id : Int, comment : String, condition : LadderNode, coils : Array[Coil]) -> Rung

    创建梯级

    SrFlipFlop

    pub(all) struct SrFlipFlop {
    q1 : Bool
    } derive(
    Debug
    )

    SR: 置位优先双稳态触发器 (Set-Dominant Bistable)

    SrFlipFlop::new

    fn SrFlipFlop::new() -> SrFlipFlop

    SrFlipFlop::tick

    fn SrFlipFlop::tick(self : SrFlipFlop, s1_val : Bool, r_val : Bool) -> Bool

    Stmt

    pub(all) enum Stmt {
    Assign(String, Expr)
    AssignAddress(PlcAddress, Expr)
    AssignField(String, String, Expr)
    If(Expr, Array[Stmt], Array[(Expr, Array[Stmt])], Array[Stmt])
    While(Expr, Array[Stmt])
    For(String, Expr, Expr, Expr?, Array[Stmt])
    FbCall(String, String, Array[(String, Expr)])
    Empty
    } derive(
    Debug
    )

    ST 语句

    TofTimer

    pub(all) struct TofTimer {
    in_state : Bool
    pt : Int64
    et : Int64
    q : Bool
    } derive(
    Debug
    )

    TOF: 断电延时定时器 (Timer Off-Delay)

    TofTimer::new

    fn TofTimer::new() -> TofTimer

    TofTimer::tick

    fn TofTimer::tick(self : TofTimer, in_val : Bool, pt_val : Int64, delta_ms : Int64) -> Unit

    TOF 周期步进刷新

    Token

    pub(all) enum Token {
    KwProgram
    KwEndProgram
    KwVar
    KwEndVar
    KwVarInput
    KwVarOutput
    KwAt
    KwIf
    KwThen
    KwElsif
    KwElse
    KwEndIf
    KwWhile
    KwEndWhile
    KwDo
    KwFor
    KwTo
    KwBy
    KwEndFor
    KwAnd
    KwOr
    KwNot
    KwXor
    KwMod
    Assign
    Equal
    NotEqual
    LessThan
    LessThanEqual
    GreaterThan
    GreaterThanEqual
    Plus
    Minus
    Star
    Slash
    LParen
    RParen
    Comma
    Semicolon
    Colon
    Dot
    Ident(String)
    BoolLit(Bool)
    IntLit(Int)
    RealLit(Double)
    TimeLit(Int64)
    StringLit(String)
    DirectAddr(PlcAddress)
    EOF
    } derive(Eq,
    Debug
    )

    Token 类型定义

    TonTimer

    pub(all) struct TonTimer {
    in_state : Bool
    pt : Int64
    et : Int64
    q : Bool
    } derive(
    Debug
    )

    TON: 通电延时定时器 (Timer On-Delay)

    TonTimer::new

    fn TonTimer::new() -> TonTimer

    TonTimer::tick

    fn TonTimer::tick(self : TonTimer, in_val : Bool, pt_val : Int64, delta_ms : Int64) -> Unit

    TON 周期步进刷新

    TonrTimer

    pub(all) struct TonrTimer {
    in_state : Bool
    pt : Int64
    et : Int64
    q : Bool
    } derive(
    Debug
    )

    TONR: 保持型通电延时定时器 (Retentive On-Delay Timer)

    TonrTimer::new

    fn TonrTimer::new() -> TonrTimer

    TonrTimer::tick

    fn TonrTimer::tick(self : TonrTimer, in_val : Bool, reset_val : Bool, pt_val : Int64, delta_ms : Int64) -> Unit

    TpTimer

    pub(all) struct TpTimer {
    in_prev : Bool
    active : Bool
    pt : Int64
    et : Int64
    q : Bool
    } derive(
    Debug
    )

    TP: 脉冲定时器 (Timer Pulse)

    TpTimer::new

    fn TpTimer::new() -> TpTimer

    TpTimer::tick

    fn TpTimer::tick(self : TpTimer, in_val : Bool, pt_val : Int64, delta_ms : Int64) -> Unit

    TP 周期步进刷新

    UnaryOp

    pub(all) enum UnaryOp {
    Not
    Neg
    } derive(Eq,
    Debug
    )

    一元运算符

    VarDecl

    pub(all) struct VarDecl {
    name : String
    var_type : String
    init_val : PlcValue?
    located_at : PlcAddress?
    } derive(
    Debug
    )

    变量声明

    compile_expr

    fn compile_expr(expr : Expr, instrs : Array[IlInstruction]) -> Unit

    将 ST 表达式编译为 IL 累加器指令序列

    compile_st_program

    fn compile_st_program(prog : Program) -> Array[IlInstruction]

    完整 ST 程序向 IL 指令流的编译入口

    compile_statement

    fn compile_statement(stmt : Stmt, instrs : Array[IlInstruction]) -> Unit

    将 ST 语句编译为 IL 字节码

    crc16_modbus

    fn crc16_modbus(bytes : Array[Int]) -> Int

    计算 Modbus RTU 16 位循环冗余校验码 (CRC-16/MODBUS, 多项式 0xA001)

    encode_rtu_request

    fn encode_rtu_request(slave_id : Int, fc : Int, addr : Int, qty_or_val : Int) -> Array[Int]

    将 Modbus 请求编码为带有 CRC16 校验的 RTU 物理字节帧

    encode_rtu_response

    fn encode_rtu_response(resp : ModbusResponse) -> Array[Int]

    将 ModbusResponse 编码为带有 CRC16 的二进制 RTU 响应帧

    ladder_node_to_expr

    fn ladder_node_to_expr(node : LadderNode) -> Expr

    将 LadderNode 编译为布尔表达式 (Expr)

    parse_plc_address

    fn parse_plc_address(addr : String) -> PlcAddress?

    将 IEC 61131-3 地址字符串 (如 "%IX0.1", "%QX0.0", "%MW10") 解析为 PlcAddress

    parse_rtu_frame

    fn parse_rtu_frame(bytes : Array[Int]) -> ModbusRequest?

    解析 RTU 二进制数据帧 (校验长度与 CRC)

    parse_uint_simple

    fn parse_uint_simple(s : String) -> Int

    纯 MoonBit 实现的轻量非负整数解析

    rung_to_stmts

    fn rung_to_stmts(rung : Rung) -> Array[Stmt]

    将单个梯级编译为对应的 ST 语句数组 (Stmt)

    version

    fn version() -> String

    版本信息