public LGEdge(LCNode _info, LGVertex _s, LGVertex _d) { this.id = 0; this.PLCInfo = _info; this.Source = _s; this.Destination = _d; }
/// <summary> /// 添加边 /// </summary> public void InsertEdge(LCNode lcnode, int sid, int did) { if (sid <= 0 || sid > vertexs.Count) { throw new ArgumentOutOfRangeException(); } if (did <= 0 || did > vertexs.Count) { throw new ArgumentOutOfRangeException(); } //Console.Write("edge {0:d} {1:d}\n", sid, did); LGEdge e = new LGEdge(lcnode, vertexs[sid - 1], vertexs[did - 1]); vertexs[sid - 1].InsertEdge(e); vertexs[did - 1].InsertEdge(e); edges.Add(e); }
/// <summary> /// 内部的表达式转逻辑图方法 /// </summary> /// <param name="expr"></param> /// <param name="lgvstart"></param> /// <param name="lgvend"></param> /// <param name="flag"></param> /// <returns></returns> static private LadderGraph _GenLadderGraph(string expr, LGVertex lgvstart = null, LGVertex lgvend = null, int flag = 0) { int estart = 0, eend = expr.Length - 1; LadderChart lchart = new LadderChart(); LadderGraph lgraph = new LadderGraph(); lgraph.LChart = lchart; // 若起始点未给定则添加 if (lgvstart == null) { lgvstart = new LGVertex(++lgvtop); } // 若结束点未给定则添加 if (lgvend == null) { lgvend = new LGVertex(++lgvtop); } //Console.WriteLine(expr.Substring(start, end - start + 1)); // 当前表达式被括号包围时拆掉括号 int bracket = 0; while (expr[estart] == '(' && expr[eend] == ')') { estart++; eend--; } // 当前单元的结尾 int uend = estart; // CASE 1:查询并处理表达式中的或运算符(优先级最高) if ((flag & FLAG_HASOR) == 0) { bracket = 0; while (uend <= eend && (bracket > 0 || expr[uend] != '|')) { if (expr[uend] == '(') { bracket++; } if (expr[uend] == ')') { bracket--; } uend++; } if (uend <= eend && expr[uend] == '|') { // 先生成或运算符前的部分的逻辑图 LadderGraph lg1 = _GenLadderGraph(expr.Substring(0, uend), lgvstart, lgvend, flag | FLAG_HASOR); // 再生成或运算符后的部分的逻辑图 LadderGraph lg2 = _GenLadderGraph(expr.Substring(uend + 2), lgvstart, lgvend, flag); // 合并两个逻辑图 lgraph.Vertexs = lg1.Vertexs.Union(lg2.Vertexs).ToList(); lgraph.Starts = lg1.Starts; lgraph.Terminates = lg1.Terminates; lgraph.Edges = lg1.Edges.Concat(lg2.Edges).ToList(); // 合并两个梯形图 /* * 因为两个字表达式属于或的关系,所以要在梯形图上体现出来并联的结构 * 合并梯形图时,要注意以下几点 * 1. 将对应的梯形图上下对接,并且首尾相连 * 2. 如果两个梯形图的宽度不一致,另一个要额外向前设立线路,然后再对接 */ // 两个相邻的梯形图元件 LCNode lcn1 = null, lcn2 = null; foreach (LCNode lcn3 in lg2.LChart.Nodes) { // 编号不能相同,所以要加上梯形图1的元件数量,建立新的编号域 lcn3.Id += lg1.LChart.Nodes.Count(); // 梯形图2放在梯形图1的下面,所以Y坐标要加上梯形图1的高度 lcn3.Y += lg1.LChart.Heigh; } // 建立合并后的新的梯形图,先将元件集合并 lchart.Nodes = lg1.LChart.Nodes.Union(lg2.LChart.Nodes).ToList(); // 宽度取两者最大,高度取两者相加 lchart.Width = Math.Max(lg1.LChart.Width, lg2.LChart.Width); lchart.Heigh = lg1.LChart.Heigh + lg2.LChart.Heigh; // 找到梯形图1的左端的最下元件 lcn1 = lg1.LChart.LeUpNode; while (lcn1.Down != null) { lcn1 = lcn1.Down; } /* * 将两个梯形图的左端对接 * 需要将上面的部分向下设立新的路线,并到达下面的左端 */ // 从该元件开始向下铺路 lcn1.VAccess = true; for (int y = lcn1.Y + 1; y <= lg1.LChart.Heigh; y++) { // 新建下面的空元件 lcn2 = new LCNode(lchart.Nodes.Count() + 1); lcn2.X = lcn1.X; lcn2.Y = y; lcn2.HAccess = false; // 将向下联通设为true,能通到下面 lcn2.VAccess = true; lcn1.Down = lcn2; lcn2.Up = lcn1; lchart.Nodes.Add(lcn2); // 完成连接后,当前元件移动到下面 lcn1 = lcn2; } // 将铺路后最下面的元件和梯形图2的左上角对接 lcn2 = lg2.LChart.LeUpNode; lcn1.Down = lcn2; lcn2.Up = lcn1; /* * 将两个梯形图的右端对接 * 需要将上面的部分向下设立新的路线,并到达下面的右端 */ // 如果梯形图1的宽度小于梯形图2 /* * 先将图1的右上角拓宽,延伸到图2一样的宽度 * 然后再向下连接,和图2的右上角相连 */ if (lg1.LChart.Width < lg2.LChart.Width) { lcn1 = lg1.LChart.RiUpNode; // 向右连接 for (int x = lg1.LChart.Width + 1; x <= lg2.LChart.Width; x++) { lcn2 = new LCNode(lchart.Nodes.Count() + 1); lcn2.X = x; lcn2.Y = lcn1.Y; lcn2.HAccess = true; lcn2.VAccess = false; lcn1.Right = lcn2; lcn2.Left = lcn1; lchart.Nodes.Add(lcn2); lcn1 = lcn2; } // 设置图1新的右上角 lg1.LChart.RiUpNode = lcn1; } else // 如果梯形图1的宽度大于梯形图2 /* * 将图2的右上角进行扩展,与图1的宽度一致 * 然后图1向下连接,直到到达图2新扩展的右下角 */ if (lg1.LChart.Width > lg2.LChart.Width) { lcn1 = lg2.LChart.RiUpNode; // 向右连接 for (int x = lg2.LChart.Width + 1; x <= lg1.LChart.Width; x++) { lcn2 = new LCNode(lchart.Nodes.Count() + 1); lcn2.X = x; lcn2.Y = lcn1.Y; lcn2.HAccess = true; lcn2.VAccess = false; lcn1.Right = lcn2; lcn2.Left = lcn1; lchart.Nodes.Add(lcn2); lcn1 = lcn2; } // 设置图2新的右上角 lg2.LChart.RiUpNode = lcn1; } /* * 经过上面的调整,这个时候图1和图2的宽度一致 * 但还是要考虑两个梯形图最右端的元件, * 要注意元件是左端向下连接的,这样连接的可能会是右端的前一个线路 * --[]-----[]-----[]-- * | * | * --[]-----[]-----[]-- * 像这种右端存在非空元件时,会连接前面的部分 * 所以要将梯形图1再向右扩展一格,右上角向右再连一条向下的线路 * 这样保证连接的是最右端 * --[]-----[]-----[]--- [right] * | * | * --[]-----[]-----[]--- */ // 如果两个梯形图其中之一的右端元件非空 if (!lg1.LChart.RiUpNode.Type.Equals(String.Empty) && !lg2.LChart.RiUpNode.Type.Equals(String.Empty)) { // 向右添加线路 lcn1 = lg1.LChart.RiUpNode; lcn2 = new LCNode(lchart.Nodes.Count() + 1); lcn2.X = lcn1.X + 1; lcn2.Y = lcn1.Y; lcn2.HAccess = false; lcn2.VAccess = true; lcn1.Right = lcn2; lcn2.Left = lcn1; lchart.Nodes.Add(lcn2); lg1.LChart.RiUpNode = lcn2; } lcn1 = lg1.LChart.RiUpNode; while (lcn1.Down != null) { lcn1 = lcn1.Down; } lcn1.VAccess = true; // 向下连接 for (int y = lcn1.Y + 1; y <= lg1.LChart.Heigh; y++) { lcn2 = new LCNode(lchart.Nodes.Count() + 1); lcn2.X = lcn1.X; lcn2.Y = y; lcn2.HAccess = false; lcn2.VAccess = true; lcn1.Down = lcn2; lcn2.Up = lcn1; lchart.Nodes.Add(lcn2); lcn1 = lcn2; } // 最下端和图2的右上角连接 lcn2 = lg2.LChart.RiUpNode; lcn1.Down = lcn2; lcn2.Up = lcn1; // 设置左上角和右上角 lchart.LeUpNode = lg1.LChart.LeUpNode; lchart.RiUpNode = lg1.LChart.RiUpNode; return(lgraph); } } // CASE 2:查询并处理表达式中的与运算符(优先级其次) if ((flag & FLAG_HASAND) == 0) { bracket = 0; uend = estart; while (uend <= eend && (bracket > 0 || expr[uend] != '&')) { if (expr[uend] == '(') { bracket++; } if (expr[uend] == ')') { bracket--; } uend++; } if (uend <= eend && expr[uend] == '&') { // 添加中间点 LGVertex lgvmidium = new LGVertex(++lgvtop); // 先生成或运算符前的部分的逻辑图 LadderGraph lg1 = _GenLadderGraph(expr.Substring(0, uend), lgvstart, lgvmidium, flag | FLAG_HASOR); // 再生成或运算符后的部分的逻辑图 LadderGraph lg2 = _GenLadderGraph(expr.Substring(uend + 2), lgvmidium, lgvend, flag); // 合并两个逻辑图 lgraph.Vertexs = lg1.Vertexs.Union(lg2.Vertexs).ToList(); lgraph.Starts = lg1.Starts; lgraph.Terminates = lg2.Terminates; lgraph.Edges = lg1.Edges.Concat(lg2.Edges).ToList(); // 图2移动到图1的右端并合并,所以编号加上图1的总数,X坐标加上图1的宽度 foreach (LCNode lcn3 in lg2.LChart.Nodes) { lcn3.Id += lg1.LChart.Nodes.Count(); lcn3.X += lg1.LChart.Width; } // 合并梯度图 lchart.Nodes = lg1.LChart.Nodes.Union(lg2.LChart.Nodes).ToList(); lchart.Width = lg1.LChart.Width + lg2.LChart.Width; lchart.Heigh = Math.Max(lg1.LChart.Width, lg2.LChart.Width); lchart.LeUpNode = lg1.LChart.LeUpNode; lchart.RiUpNode = lg2.LChart.RiUpNode; // 图1和图2首尾相接 lg1.LChart.RiUpNode.Right = lg2.LChart.LeUpNode; lg2.LChart.LeUpNode.Left = lg1.LChart.RiUpNode; // 图1需要向右连接 lg1.LChart.RiUpNode.HAccess = true; return(lgraph); } } // CASE 3:当前为单一单元 // 新建一个新的逻辑图 lgraph.Starts.Add(lgvstart); lgraph.Terminates.Add(lgvend); lgraph.Vertexs.Add(lgvstart); lgraph.Vertexs.Add(lgvend); LCNode lcn = new LCNode(0); LGEdge lge = new LGEdge(lcn, lgvstart, lgvend); lgvstart.Edges.Add(lge); lgvend.BackEdges.Add(lge); lgraph.Edges.Add(lge); // 新建一个梯度图 lchart.Width = lchart.Heigh = 1; lchart.Insert(lcn); // 对表达式进行解析 // 函数调用形式表示的功能指令(func(a,b,c)) if (expr[eend] == ')') { // 找到括号的起始位置和终止位置 int ebstart = estart; int ebend = eend; while (expr[ebstart] != '(') { ebstart++; } // 得到函数名称和参数集合 string fname = expr.Substring(estart, ebstart - estart); string[] fargs = expr.Substring(ebstart + 1, ebend - ebstart - 1).Split(','); // 转换为LadderChart模式 lcn.Type = fname; if (fargs.Length > 1) { lcn[1] = fargs[0]; } if (fargs.Length > 2) { lcn[2] = fargs[1]; } if (fargs.Length > 3) { lcn[3] = fargs[2]; } if (fargs.Length > 4) { lcn[4] = fargs[3]; } if (fargs.Length > 5) { lcn[5] = fargs[4]; } return(lgraph); } // 识别开始的非符号 if (expr[estart] == '!') { // 识别非符号后面的立即符号( !imM0 ) if (expr[estart + 1] == 'i' && expr[estart + 2] == 'm') { lcn.Type = "LDIIM"; lcn[1] = expr.Substring(estart + 3, eend - estart - 2); return(lgraph); } // 一般的非符号( !M0 ) lcn.Type = "LDI"; lcn[1] = expr.Substring(estart + 1, eend - estart); return(lgraph); } // 识别上升沿符号(ueM0) if (expr[estart] == 'u' && expr[estart + 1] == 'e') { lcn.Type = "LDP"; lcn[1] = expr.Substring(estart + 2, eend - estart - 1); return(lgraph); } // 识别下降沿符号(deM0) if (expr[estart] == 'd' && expr[estart + 1] == 'e') { lcn.Type = "LDF"; lcn[1] = expr.Substring(estart + 2, eend - estart - 1); return(lgraph); } // 识别立即符号(imM0) if (expr[estart] == 'i' && expr[estart + 1] == 'm') { lcn.Type = "LDIM"; lcn[1] = expr.Substring(estart + 2, eend - estart - 1); return(lgraph); } // 比较表达式的长度都不小于6 if (eend - estart > 4) { // 找到比较符的位置 int op = estart + 2; while (expr[op] != '=' && expr[op] != '<' && expr[op] != '>') { op++; } // 识别比较符前的数据类型 /* * int datatype = 0; * switch (expr[op - 1]) * { * case 'w': datatype = 1; break; * case 'd': datatype = 2; break; * case 'f': datatype = 3; break; * } */ // 等比较(M0w=M1) if (expr[op] == '=') { switch (expr[op - 1]) { case 'w': lcn.Type = "LDWEQ"; break; case 'd': lcn.Type = "LDDEQ"; break; case 'f': lcn.Type = "LDFEQ"; break; } lcn[1] = expr.Substring(estart, op - 1 - estart); lcn[2] = expr.Substring(op + 1, eend - op); return(lgraph); } // 不等比较(M0w<>M1) if (expr[op] == '<' && expr[op + 1] == '>') { switch (expr[op - 1]) { case 'w': lcn.Type = "LDWNE"; break; case 'd': lcn.Type = "LDDNE"; break; case 'f': lcn.Type = "LDFNE"; break; } lcn[1] = expr.Substring(estart, op - 1 - estart); lcn[2] = expr.Substring(op + 2, eend - op - 1); return(lgraph); } // 小等比较(M0w<=M1) if (expr[op] == '<' && expr[op + 1] == '=') { if (expr[op] == '<' && expr[op + 1] == '>') { switch (expr[op - 1]) { case 'w': lcn.Type = "LDWLE"; break; case 'd': lcn.Type = "LDDLE"; break; case 'f': lcn.Type = "LDFLE"; break; } lcn[1] = expr.Substring(estart, op - 1 - estart); lcn[2] = expr.Substring(op + 2, eend - op - 1); return(lgraph); } return(lgraph); } // 大等比较(M0w>=M1) if (expr[op] == '>' && expr[op + 1] == '=') { if (expr[op] == '<' && expr[op + 1] == '>') { switch (expr[op - 1]) { case 'w': lcn.Type = "LDWGE"; break; case 'd': lcn.Type = "LDDGE"; break; case 'f': lcn.Type = "LDFGE"; break; } lcn[1] = expr.Substring(estart, op - 1 - estart); lcn[2] = expr.Substring(op + 2, eend - op - 1); return(lgraph); } return(lgraph); } // 小于比较(M0w<M1) if (expr[op] == '<') { switch (expr[op - 1]) { case 'w': lcn.Type = "LDWL"; break; case 'd': lcn.Type = "LDDL"; break; case 'f': lcn.Type = "LDFL"; break; } lcn[1] = expr.Substring(estart, op - 1 - estart); lcn[2] = expr.Substring(op + 1, eend - op); return(lgraph); } // 大于比较(M0w>M1) if (expr[op] == '>') { switch (expr[op - 1]) { case 'w': lcn.Type = "LDWG"; break; case 'd': lcn.Type = "LDDG"; break; case 'f': lcn.Type = "LDFG"; break; } lcn[1] = expr.Substring(estart, op - 1 - estart); lcn[2] = expr.Substring(op + 1, eend - op); return(lgraph); } } // 读取位(M0) lcn.Type = "LD"; lcn[1] = expr.Substring(estart, eend - estart + 1); return(lgraph); }