public NFA determinizeNFA(NFA toConvert)
	{
		// Store the NFA's states in a Hashtable for easy reference.
		Hashtable<Symbol,NFAState> singleIDStates = new Hashtable<Symbol,NFAState>();
		for(NFAState s : toConvert.getStates())
		{
			Symbol sym = s.getIdentifier().iterator().next();
			singleIDStates.put(sym,s);
		}
		// The states of the new DFA.
		DynHashSet<NFAState> states = new DynHashSet<NFAState>();
		// A FIFO queue to perform a nondeterministic breadth-first search of the NFA.
		LinkedList<NFAState> stateQueue = new LinkedList<NFAState>();
		// Add the epsilon-closure of the start state to the BFS queue.
		NFAState startState = new NFAState(epsilonClosure(toConvert.getStartState()),null);
		states.put(startState);
		stateQueue.offer(startState);
		// For each DFA state encountered:
		while(!stateQueue.isEmpty())
		{
			NFAState front = stateQueue.poll();
			// The DFA states reachable from this DFA state.
			Hashtable< CharacterRange,HashSet<Symbol> > nextStates = new Hashtable< CharacterRange,HashSet<Symbol> >();
			// For every NFA state represented by this DFA state:
			for(Symbol sym : front.getIdentifier())
			{
				// Add the accepting symbols of the NFA state to the DFA state.
				front.addAcceptSyms(singleIDStates.get(sym).getAccepts());
				// For every transition from the NFA state:
				for(Pair<CharacterRange,NFAState> pair : singleIDStates.get(sym))
				{
					// If it is an epsilon-transition, skip it
					if(pair.first().equals(new CharacterRange(NFAState.EmptyChar))) continue;
					// Else:
					// If there are no transitions yet recorded for the alphabet
					// symbol in this transition, create a table entry.
					if(!nextStates.containsKey(pair.first())) nextStates.put(pair.first(),new HashSet<Symbol>());
					// Add all states in the epsilon-closure of the transition's
					// destination state to the DFA destination state.
					nextStates.get(pair.first()).addAll(epsilonClosure(pair.second()));
				}
			}
			// For each character for which there was a transition recorded:
			for(CharacterRange c : nextStates.keySet())
			{
				// Create a new destination state from the set of NFA states obtained above.
				HashSet<Symbol> epsClosures = nextStates.get(c);
				NFAState newState = new NFAState(epsClosures,null);
				// If the DFA already contains the new state, add a transition to it from the current state.
				if(states.contains(newState))
				{
					front.addTransition(c,states.get(newState));
				}
				// Else:
				else
				{
					// Put the new state in the DFA.
					states.put(newState);
					// Add a transition to it from the current state.
					front.addTransition(c,newState);
					// Put it in the BFS queue.
					stateQueue.offer(newState);
				}
			}
		}
		// Return an NFA object (DFA) of the new states.
		HashSet<NFAState> newStates = new HashSet<NFAState>();
		for(NFAState ns : states) newStates.add(ns);
		return new NFA(newStates,startState);
	}