gui效果图,gui代码太长了就不贴了

编译结果
LD,test3
NOT,
STORE,TMP1
LD,test1
OR,
LD,TMP1
OUT,test2
LD,TMP1
RST,test
LD,TMP1
OUT,test22
LD,TMP1
OUT,test4
LD,TMP1
CALL,放料
编译器代码
using System.Collections.Generic;
using System.Linq;
namespace LDEdit
{
public class LadderCompiler
{
private readonly ConnectionManager _connManager;
private readonly Dictionary<CellState, CellState> _cellStateMap;
private Dictionary<CellState, string> _commonNodes = new Dictionary<CellState, string>();
private int _tempCounter = 0;
private Dictionary<CellState, List<List<CellState>>> _coilPathCache = new Dictionary<CellState, List<List<CellState>>>();
public LadderCompiler(ConnectionManager connManager, List<CellState> cells)
{
_connManager = connManager;
_cellStateMap = cells.ToDictionary(c => c);
}
public List<Instruction> Compile()
{
var instructions = new List<Instruction>();
var allPaths = new List<List<CellState>>();
// 第一阶段:收集所有线圈路径
var outputCoils = _cellStateMap.Values
.Where(c => IsOutputType(c.cellType))
.OrderBy(c => c.row)
.ToList();
foreach (var coil in outputCoils)
{
var branches = FindAllBranches(coil);
_coilPathCache[coil] = branches;
allPaths.AddRange(branches);
}
// 第二阶段:分析公共节点
var commonNodes = AnalyzeCommonNodes(allPaths);
GenerateCommonLogic(commonNodes, instructions);
// 第三阶段:生成优化后的指令
foreach (var coil in outputCoils)
{
CompileOptimizedCoil(coil, instructions);
}
return instructions;
}
private Dictionary<CellState, int> AnalyzeCommonNodes(List<List<CellState>> allPaths)
{
var nodeFrequency = new Dictionary<CellState, int>();
var visited = new HashSet<CellState>();
foreach (var path in allPaths)
{
var reversed = Enumerable.Reverse(path).ToList();
foreach (var cell in reversed)
{
if (IsContactType(cell.cellType))
{
if (!nodeFrequency.ContainsKey(cell))
nodeFrequency[cell] = 0;
nodeFrequency[cell]++;
}
}
}
return nodeFrequency
.Where(kv => kv.Value > 1)
.ToDictionary(kv => kv.Key, kv => kv.Value);
}
private void GenerateCommonLogic(Dictionary<CellState, int> commonNodes, List<Instruction> instructions)
{
foreach (var node in commonNodes.Keys.OrderByDescending(n => n.row))
{
var tmpVar = $"TMP{++_tempCounter}";
_commonNodes[node] = tmpVar;
var branches = FindAllBranches(node);
bool firstBranch = true;
foreach (var branch in branches)
{
var trimmed = TrimBranch(branch, commonNodes.Keys);
CompileBranch(trimmed, instructions);
if (!firstBranch)
{
instructions.Add(new Instruction { Code = OpCode.OR });
}
firstBranch = false;
}
instructions.Add(new Instruction { Code = OpCode.STORE, Operand = tmpVar });
}
}
private List<CellState> TrimBranch(List<CellState> branch, IEnumerable<CellState> commonNodes)
{
var result = new List<CellState>();
foreach (var cell in branch)
{
if (commonNodes.Contains(cell) && cell != branch.Last())
break;
result.Add(cell);
}
return result;
}
private void CompileOptimizedCoil(CellState coil, List<Instruction> instructions)
{
var branches = _coilPathCache[coil];
bool needsOR = branches.Count > 1;
foreach (var branch in branches)
{
var optimized = ApplyOptimizations(branch);
CompileBranch(optimized, instructions);
if (needsOR)
{
instructions.Add(new Instruction { Code = OpCode.OR });
needsOR = false;
}
}
AddOutputInstruction(coil, instructions);
}
private List<CellState> ApplyOptimizations(List<CellState> branch)
{
var optimized = new List<CellState>();
foreach (var cell in branch)
{
if (_commonNodes.TryGetValue(cell, out var tmpVar))
{
optimized.Add(CreateTempCell(tmpVar));
break; // 截断后续路径
}
optimized.Add(cell);
}
return optimized;
}
private CellState CreateTempCell(string tmpVar) =>
new CellState { cellType = CellType.TempVariable, SymbolName = tmpVar };
private List<List<CellState>> FindAllBranches(CellState endCell)
{
var branches = new List<List<CellState>>();
var visited = new HashSet<CellState>();
var currentPath = new Stack<CellState>();
void Backtrack(CellState current)
{
if (current == null || visited.Contains(current)) return;
visited.Add(current);
currentPath.Push(current);
var predecessors = _connManager.GetPredecessors(current);
if (predecessors.Count == 0)
{
branches.Add(currentPath.Reverse().ToList());
}
else
{
foreach (var pred in predecessors)
{
Backtrack(pred);
}
}
currentPath.Pop();
visited.Remove(current);
}
Backtrack(endCell);
return branches;
}
private void CompileBranch(List<CellState> branch, List<Instruction> instructions)
{
bool firstContact = true;
foreach (var cell in branch)
{
if (cell.cellType == CellType.TempVariable)
{
instructions.Add(new Instruction { Code = OpCode.LD, Operand = cell.SymbolName });
firstContact = false;
continue;
}
if (!IsContactType(cell.cellType)) continue;
instructions.Add(new Instruction { Code = OpCode.LD, Operand = cell.SymbolName });
if (cell.cellType == CellType.Close)
{
instructions.Add(new Instruction { Code = OpCode.NOT });
}
if (!firstContact)
{
instructions.Add(new Instruction { Code = OpCode.AND });
}
firstContact = false;
}
}
private void AddOutputInstruction(CellState coil, List<Instruction> instructions)
{
switch (coil.cellType)
{
case CellType.OutputCoil:
instructions.Add(new Instruction { Code = OpCode.OUT, Operand = coil.SymbolName });
break;
case CellType.SetCoil:
instructions.Add(new Instruction { Code = OpCode.SET, Operand = coil.SymbolName });
break;
case CellType.ResetCoil:
instructions.Add(new Instruction { Code = OpCode.RST, Operand = coil.SymbolName });
break;
case CellType.CallCoil:
instructions.Add(new Instruction { Code = OpCode.CALL, Operand = coil.SymbolName });
break;
}
}
private bool IsContactType(CellType type) =>
type == CellType.Open || type == CellType.Close;
private bool IsOutputType(CellType type) =>
type == CellType.OutputCoil || type == CellType.SetCoil || type == CellType.ResetCoil||type==CellType.CallCoil;
}
}
虚拟机实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LDEdit
{
// 增强虚拟机实现
public class VirtualMachine
{
private readonly Dictionary<string, bool> _variables = new Dictionary<string, bool>();
private readonly Dictionary<string, bool> _latched = new Dictionary<string, bool>();
private Stack<bool> _evalStack = new Stack<bool>();
public event Action<string,bool> VariableChanged;
public void Execute(List<Instruction> program)
{
_evalStack.Clear();
foreach (var inst in program)
{
switch (inst.Code)
{
case OpCode.LOAD:
_evalStack.Push(GetVariableValue(inst.Operand));
break;
case OpCode.NOT when _evalStack.Count > 0:
_evalStack.Push(!_evalStack.Pop());
break;
case OpCode.AND when _evalStack.Count >= 2:
_evalStack.Push(_evalStack.Pop() & _evalStack.Pop());
break;
case OpCode.OR when _evalStack.Count >= 2:
_evalStack.Push(_evalStack.Pop() | _evalStack.Pop());
break;
case OpCode.OUT when _evalStack.Count > 0:
UpdateVariable(inst.Operand, _evalStack.Pop());
break;
case OpCode.SET:
if (_evalStack.Pop())
SetLatched(inst.Operand, true);
break;
case OpCode.RST:
if (_evalStack.Pop())
SetLatched(inst.Operand, false);
break;
}
}
}
public void AddInput(string name, bool value)
{
if (_variables.ContainsKey(name))
{
UpdateInput(name, value);
}
else
{
_variables.Add(name, value);
VariableChanged?.Invoke(name,value);
}
}
public void UpdateInput(string name, bool value)
{
if (_variables.TryGetValue(name, out var current) && current == value) return;
_variables[name] = value;
VariableChanged?.Invoke(name, value);
}
private bool GetVariableValue(string name)
{
// 优先返回锁存值
if (_latched.TryGetValue(name, out var latched)) return latched;
return _variables.TryGetValue(name, out var value) && value;
}
private void UpdateVariable(string name, bool value)
{
if (_variables.TryGetValue(name, out var current) && current == value) return;
_variables[name] = value;
VariableChanged?.Invoke(name, value);
}
private void SetLatched(string name, bool value)
{
if (_latched.TryGetValue(name, out var current) && current == value) return;
_latched[name] = value;
VariableChanged?.Invoke(name,value);
}
}
}