///| IEC 61131-3 结构化文本 (ST) 到指令表 (IL) 字节码编译器
///|
/// 将 ST 表达式编译为 IL 累加器指令序列
pub fn compile_expr(expr : Expr, instrs : Array[IlInstruction]) -> Unit {
match expr {
Expr::Literal(val) =>
instrs.push(IlInstruction::with_val(IlOpcode::Ld, val))
Expr::Variable(name) =>
instrs.push(IlInstruction::with_var(IlOpcode::Ld, name))
Expr::DirectAddress(addr) =>
instrs.push(IlInstruction::with_var(IlOpcode::Ld, addr.to_key()))
Expr::FieldAccess(inst, field) =>
instrs.push(IlInstruction::with_var(IlOpcode::Ld, "\{inst}.\{field}"))
Expr::Unary(op, sub) =>
match op {
UnaryOp::Not =>
match sub {
Expr::Variable(name) =>
instrs.push(IlInstruction::with_var(IlOpcode::Ldn, name))
Expr::DirectAddress(addr) =>
instrs.push(IlInstruction::with_var(IlOpcode::Ldn, addr.to_key()))
_ => {
compile_expr(sub, instrs)
// 累加器取反: Xor TRUE
instrs.push(
IlInstruction::with_val(IlOpcode::Xor, PlcValue::Bool(true)),
)
}
}
UnaryOp::Neg => {
compile_expr(sub, instrs)
// 0 - acc
instrs.push(IlInstruction::with_val(IlOpcode::Mul, PlcValue::Int(-1)))
}
}
Expr::Binary(left, op, right) => {
// 先编译左表达式加载到累加器
compile_expr(left, instrs)
// 根据右表达式的类型与运算符发射二元操作指令
match right {
Expr::Literal(val) => {
let il_op = match op {
BinaryOp::Add => IlOpcode::Add
BinaryOp::Sub => IlOpcode::Sub
BinaryOp::Mul => IlOpcode::Mul
BinaryOp::Div => IlOpcode::Div
BinaryOp::Mod => IlOpcode::Mod
BinaryOp::Eq => IlOpcode::Eq
BinaryOp::Neq => IlOpcode::Ne
BinaryOp::Gt => IlOpcode::Gt
BinaryOp::Lt => IlOpcode::Lt
BinaryOp::Gte => IlOpcode::Ge
BinaryOp::Lte => IlOpcode::Le
BinaryOp::And => IlOpcode::And
BinaryOp::Or => IlOpcode::Or
BinaryOp::Xor => IlOpcode::Xor
}
instrs.push(IlInstruction::with_val(il_op, val))
}
Expr::Variable(name) => {
let il_op = match op {
BinaryOp::Add => IlOpcode::Add
BinaryOp::Sub => IlOpcode::Sub
BinaryOp::Mul => IlOpcode::Mul
BinaryOp::Div => IlOpcode::Div
BinaryOp::Mod => IlOpcode::Mod
BinaryOp::Eq => IlOpcode::Eq
BinaryOp::Neq => IlOpcode::Ne
BinaryOp::Gt => IlOpcode::Gt
BinaryOp::Lt => IlOpcode::Lt
BinaryOp::Gte => IlOpcode::Ge
BinaryOp::Lte => IlOpcode::Le
BinaryOp::And => IlOpcode::And
BinaryOp::Or => IlOpcode::Or
BinaryOp::Xor => IlOpcode::Xor
}
instrs.push(IlInstruction::with_var(il_op, name))
}
_ => {
// 针对更复杂的右子树表达式,先存储中间值
let temp_name = "__temp_st_right"
compile_expr(right, instrs)
instrs.push(IlInstruction::with_var(IlOpcode::St, temp_name))
compile_expr(left, instrs)
instrs.push(IlInstruction::with_var(IlOpcode::And, temp_name))
}
}
}
}
}
///|
/// 将 ST 语句编译为 IL 字节码
pub fn compile_statement(stmt : Stmt, instrs : Array[IlInstruction]) -> Unit {
match stmt {
Stmt::Assign(var_name, expr) => {
compile_expr(expr, instrs)
instrs.push(IlInstruction::with_var(IlOpcode::St, var_name))
}
Stmt::AssignAddress(addr, expr) => {
compile_expr(expr, instrs)
instrs.push(IlInstruction::with_var(IlOpcode::St, addr.to_key()))
}
Stmt::AssignField(inst, field, expr) => {
compile_expr(expr, instrs)
instrs.push(IlInstruction::with_var(IlOpcode::St, "\{inst}.\{field}"))
}
Stmt::If(cond, then_stmts, _, else_stmts) => {
compile_expr(cond, instrs)
// 若累加器为 FALSE 则跳转至 else 分支,此处记录跳转指令索引
let jmp_idx = instrs.length()
instrs.push(IlInstruction::new(IlOpcode::Jmpcn(0))) // 占位符
// 编译 then 分支
for s in then_stmts {
compile_statement(s, instrs)
}
// 如果有 else 分支
if else_stmts.length() > 0 {
let skip_else_idx = instrs.length()
instrs.push(IlInstruction::new(IlOpcode::Jmp(0))) // 跳过 else 占位
// 回填条件跳转地址
instrs[jmp_idx] = IlInstruction::new(IlOpcode::Jmpcn(skip_else_idx + 1))
for s in else_stmts {
compile_statement(s, instrs)
}
let end_idx = instrs.length()
instrs[skip_else_idx] = IlInstruction::new(IlOpcode::Jmp(end_idx))
} else {
let end_idx = instrs.length()
instrs[jmp_idx] = IlInstruction::new(IlOpcode::Jmpcn(end_idx))
}
}
Stmt::While(cond, body) => {
let loop_start = instrs.length()
compile_expr(cond, instrs)
let exit_jump_idx = instrs.length()
instrs.push(IlInstruction::new(IlOpcode::Jmpcn(0)))
for s in body {
compile_statement(s, instrs)
}
instrs.push(IlInstruction::new(IlOpcode::Jmp(loop_start)))
let loop_end = instrs.length()
instrs[exit_jump_idx] = IlInstruction::new(IlOpcode::Jmpcn(loop_end))
}
_ => ()
}
}
///|
/// 完整 ST 程序向 IL 指令流的编译入口
pub fn compile_st_program(prog : Program) -> Array[IlInstruction] {
let instrs = []
for s in prog.statements {
compile_statement(s, instrs)
}
instrs.push(IlInstruction::new(IlOpcode::Halt))
instrs
}