当前位置: 首页 > article >正文

C#使用winform实现简单的梯形图指令编译和执行,带编译器和虚拟机代码

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);
        }
    }

}


http://www.kler.cn/a/577021.html

相关文章:

  • 性能测试和Jmeter
  • 使用 Prim 算法生成了最小生成树, 使用 Fleury 算法生成了欧拉回路,尝试找到了一个简单的哈密尔顿圈。
  • DTO 命名规范指南
  • Cursor 使用经验,一个需求开发全流程
  • 阿里云CTF2025 ---Web
  • Python条件语句:if-elif vs match 详解
  • 深入理解Vue Router:构建单页应用的导航利器
  • 【FPGA】导航
  • 常用Shell脚本总结
  • SQL Server核心知识总结
  • C# 异步任务队列封装
  • RocketMQ提供了哪些过滤机制?
  • OpenSSL 使用方法汇总:从证书管理到加密解密全解析
  • 【从0到1构建实时聊天系统:Spring Boot + Vue3 + WebSocket全栈实战】
  • leetcode日记(86)恢复二叉搜索树
  • 无线电家电遥控系统的设计(论文+源码)
  • pyside6学习专栏(十一):在PySide6中实现一简易的画板程序
  • 备赛蓝桥杯之第十五届职业院校组省赛第六题:简易JSX解析器
  • Unity Shader编程】之基础纹理
  • ESP8266 NodeMCU 与 Atmega16 微控制器连接以发送电子邮件