public void SequentialComposition(NFA nfa) { Dictionary <State, Dictionary <char, HashSet <State> > > transitions = nfa.GetTransitions(); Dictionary <State, State> transform = new Dictionary <State, State> (); foreach (State state in nfa.GetStates()) { if (state == 0) { transform [state] = _finalState; } else { transform [state] = AddState(); } } foreach (State state1 in transitions.Keys) { foreach (char c in transitions[state1].Keys) { foreach (State state2 in transitions[state1][c]) { AddTransition(transform [state1], c, transform [state2]); } } } _finalState = transform [nfa.GetFinalState()]; }
static private void ParseTreeNode(Node node, List <Entry> entryList) { List <Node> children = null; HashSet <char> alphabet = null; NFA curNFA = null; State state1, state2, chkState1, chkState2; switch (node.GetNodeType()) { case Node.Type.TENTRY: children = node.GetChildren(); if (children [0].GetNodeType() != Node.Type.TDIRPATH) { throw new CloudMakefile.ParseException("A TDIRPATH node is expected as the first node of a " + "TENTRY node."); } if (children [1].GetNodeType() != Node.Type.TNAME) { throw new CloudMakefile.ParseException("A TNAME node is expected as the second node of a TENTRY " + "node."); } if (children [2].GetNodeType() != Node.Type.TXMLPATH) { throw new CloudMakefile.ParseException("A TXMLPATH node is expected as the third node of a " + "TENTRY node."); } ParseTreeNode(children [0], entryList); ParseTreeNode(children [1], entryList); curNFA = EnsureLastNFA(entryList); state1 = curNFA.GetFinalState(); state2 = curNFA.AddState(); curNFA.AddTransition(state1, '.', state2); state1 = state2; state2 = curNFA.AddState(); curNFA.AddTransition(state1, 'x', state2); state1 = state2; state2 = curNFA.AddState(); curNFA.AddTransition(state1, 'm', state2); state1 = state2; state2 = curNFA.AddState(); curNFA.AddTransition(state1, 'l', state2); curNFA.SetFinalState(state2); ParseTreeNode(children [2], entryList); break; case Node.Type.TEVENT: children = node.GetChildren(); if (children [0].GetNodeType() != Node.Type.TDIRPATH) { throw new CloudMakefile.ParseException("A TDIRPATH node is expected as the first node of a " + "TEVENT node."); } if (children [1].GetNodeType() != Node.Type.TNAME) { throw new CloudMakefile.ParseException("A TNAME node is expected as the second node of a TEVENT " + "node."); } ParseTreeNode(children [0], entryList); ParseTreeNode(children [1], entryList); break; case Node.Type.TDIRPATH: children = node.GetChildren(); foreach (Node child in children) { if (child.GetNodeType() != Node.Type.TNAME) { throw new CloudMakefile.ParseException("A TNAME node is expected as the child node of a " + "TDIRPATH node."); } ParseTreeNode(child, entryList); curNFA = EnsureLastNFA(entryList); state1 = curNFA.GetFinalState(); state2 = curNFA.AddState(); curNFA.AddTransition(state1, Path.DirectorySeparatorChar, state2); curNFA.SetFinalState(state2); } break; case Node.Type.TXMLPATH: Node lastNode = new Node("ASTERISK(ATOM(SEQUENCE(CHOICE(RANGE(CHAR(A),CHAR(Z)),RANGE(CHAR(a)," + "CHAR(z)),RANGE(CHAR(0),CHAR(9)),CHAR(@),CHAR(_)))))"); children = node.GetChildren(); foreach (Node child in children) { if (child.GetNodeType() != Node.Type.TNAME) { throw new CloudMakefile.ParseException("A TNAME node is expected as the child node of a " + "TXMLPATH node."); } curNFA = EnsureLastNFA(entryList); state1 = curNFA.GetFinalState(); state2 = curNFA.AddState(); curNFA.AddTransition(state1, '{', state2); curNFA.SetFinalState(state2); ParseTreeNode(child, entryList); curNFA = EnsureLastNFA(entryList); state1 = curNFA.GetFinalState(); state2 = curNFA.AddState(); curNFA.AddTransition(state1, '}', state2); curNFA.SetFinalState(state2); } curNFA = EnsureLastNFA(entryList); chkState1 = curNFA.GetFinalState(); state1 = chkState1; state2 = curNFA.AddState(); curNFA.AddTransition(state1, '{', state2); curNFA.SetFinalState(state2); ParseTreeNode(lastNode, entryList); state1 = curNFA.GetFinalState(); state2 = curNFA.AddState(); chkState2 = state2; curNFA.AddTransition(state1, '}', state2); curNFA.SetFinalState(state2); curNFA.AddTransition(chkState1, Char.MinValue, chkState2); curNFA.AddTransition(chkState2, Char.MinValue, chkState1); break; case Node.Type.TNAME: children = node.GetChildren(); foreach (Node child in children) { if (child.GetNodeType() == Node.Type.TSEQUENCE) { ParseTreeNode(child, entryList); } else if (child.GetNodeType() == Node.Type.TVAR) { ParseTreeNode(child, entryList); } else { throw new CloudMakefile.ParseException("A TSEQUENCE or TVAR node is expected as the child " + "node of a TNAME node."); } } break; case Node.Type.TSEQUENCE: children = node.GetChildren(); foreach (Node child in children) { if ((child.GetNodeType() != Node.Type.TASTERISK) && (child.GetNodeType() != Node.Type.TPLUS) && (child.GetNodeType() != Node.Type.TQUESTIONMARK) && (child.GetNodeType() != Node.Type.TCHAR) && (child.GetNodeType() != Node.Type.TCHOICE) && (child.GetNodeType() != Node.Type.TNO_CHOICE) && (child.GetNodeType() != Node.Type.TUNION) && (child.GetNodeType() != Node.Type.TATOM)) { throw new CloudMakefile.ParseException("An appropriate node is expected as the child node " + "of a TSEQUENCE node."); } ParseTreeNode(child, entryList); } break; case Node.Type.TATOM: children = node.GetChildren(); if (children [0].GetNodeType() != Node.Type.TSEQUENCE) { throw new CloudMakefile.ParseException("A TSEQUENCE node is expected as the first node of a " + "TATOM node."); } ParseTreeNode(children [0], entryList); break; case Node.Type.TASTERISK: children = node.GetChildren(); if ((children [0].GetNodeType() != Node.Type.TCHAR) && (children [0].GetNodeType() != Node.Type.TCHOICE) && (children [0].GetNodeType() != Node.Type.TNO_CHOICE) && (children [0].GetNodeType() != Node.Type.TUNION) && (children [0].GetNodeType() != Node.Type.TATOM)) { throw new CloudMakefile.ParseException("An appropriate node is expected as the child node of a " + "TASTERISK node."); } curNFA = EnsureLastNFA(entryList); chkState1 = curNFA.GetFinalState(); ParseTreeNode(children [0], entryList); chkState2 = curNFA.GetFinalState(); curNFA.AddTransition(chkState1, Char.MinValue, chkState2); curNFA.AddTransition(chkState2, Char.MinValue, chkState1); break; case Node.Type.TPLUS: children = node.GetChildren(); if ((children [0].GetNodeType() != Node.Type.TCHAR) && (children [0].GetNodeType() != Node.Type.TCHOICE) && (children [0].GetNodeType() != Node.Type.TNO_CHOICE) && (children [0].GetNodeType() != Node.Type.TUNION) && (children [0].GetNodeType() != Node.Type.TATOM)) { throw new CloudMakefile.ParseException("An appropriate node is expected as the child node of a " + "TPLUS node."); } curNFA = EnsureLastNFA(entryList); chkState1 = curNFA.GetFinalState(); ParseTreeNode(children [0], entryList); chkState2 = curNFA.GetFinalState(); curNFA.AddTransition(chkState2, Char.MinValue, chkState1); break; case Node.Type.TQUESTIONMARK: children = node.GetChildren(); if ((children [0].GetNodeType() != Node.Type.TCHAR) && (children [0].GetNodeType() != Node.Type.TCHOICE) && (children [0].GetNodeType() != Node.Type.TNO_CHOICE) && (children [0].GetNodeType() != Node.Type.TUNION) && (children [0].GetNodeType() != Node.Type.TATOM)) { throw new CloudMakefile.ParseException("An appropriate node is expected as the child node of a " + "TQUESTIONMARK node."); } curNFA = EnsureLastNFA(entryList); chkState1 = curNFA.GetFinalState(); ParseTreeNode(children [0], entryList); chkState2 = curNFA.GetFinalState(); curNFA.AddTransition(chkState1, Char.MinValue, chkState2); break; case Node.Type.TCHOICE: alphabet = new HashSet <char> (); children = node.GetChildren(); foreach (Node child in children) { if ((child.GetNodeType() != Node.Type.TCHAR) && (child.GetNodeType() != Node.Type.TRANGE)) { throw new CloudMakefile.ParseException("A TCHAR and a TRANGE node is expected as the child " + "node of a TCHOICE node."); } if (child.GetNodeType() == Node.Type.TRANGE) { Tuple <char, char> range = child.GetRange(); for (char c = range.Item1; c <= range.Item2; c++) { alphabet.Add(c); } } else { alphabet.Add(child.GetChar()); } } curNFA = EnsureLastNFA(entryList); state1 = curNFA.GetFinalState(); state2 = curNFA.AddState(); foreach (char c in alphabet) { curNFA.AddTransition(state1, c, state2); } curNFA.SetFinalState(state2); break; case Node.Type.TNO_CHOICE: alphabet = new HashSet <char> (); for (char c = 'A'; c <= 'Z'; c++) { alphabet.Add(c); } for (char c = 'a'; c <= 'z'; c++) { alphabet.Add(c); } for (char c = '0'; c <= '9'; c++) { alphabet.Add(c); } alphabet.Add('_'); alphabet.Add('@'); children = node.GetChildren(); foreach (Node child in children) { if (child.GetNodeType() == Node.Type.TRANGE) { Tuple <char, char> range = child.GetRange(); for (char c = range.Item1; c <= range.Item2; c++) { alphabet.Remove(c); } } else { alphabet.Remove(child.GetChar()); } } state1 = curNFA.GetFinalState(); state2 = curNFA.AddState(); curNFA = EnsureLastNFA(entryList); foreach (char c in alphabet) { curNFA.AddTransition(state1, c, state2); } curNFA.SetFinalState(state2); break; case Node.Type.TUNION: children = node.GetChildren(); if (children [0].GetNodeType() != Node.Type.TSEQUENCE) { throw new CloudMakefile.ParseException("A TSEQUENCE node is expected as the first node of a " + "TUNION node."); } if (children [1].GetNodeType() != Node.Type.TSEQUENCE) { throw new CloudMakefile.ParseException("A TSEQUENCE node is expected as the second node of a " + "TUNION node."); } curNFA = EnsureLastNFA(entryList); state1 = curNFA.GetFinalState(); ParseTreeNode(children [0], entryList); chkState1 = curNFA.GetFinalState(); curNFA.SetFinalState(state1); ParseTreeNode(children [1], entryList); chkState2 = curNFA.GetFinalState(); state2 = curNFA.AddState(); curNFA.AddTransition(chkState1, Char.MinValue, state2); curNFA.AddTransition(chkState2, Char.MinValue, state2); curNFA.SetFinalState(state2); break; case Node.Type.TVAR: string varName = CloudMakefile.ParseString(node); entryList.Add(new Entry(varName)); break; case Node.Type.TCHAR: char character = node.GetChar(); curNFA = EnsureLastNFA(entryList); state1 = curNFA.GetFinalState(); state2 = curNFA.AddState(); curNFA.AddTransition(state1, character, state2); curNFA.SetFinalState(state2); break; default: throw new CloudMakefile.ParseException("Unhandled node type: " + node.GetNodeType().ToString()); } }