/// <summary> /// Generates the lexer's binary data /// </summary> /// <param name="file">The file to output to</param> public void Generate(string file) { BinaryWriter writer = new BinaryWriter(new FileStream(file, FileMode.Create)); writer.Write((uint)dfa.StatesCount); uint offset = 0; List <int> currentContexts = new List <int>(); foreach (Automata.DFAState state in dfa.States) { writer.Write(offset); offset += 3 + 256; currentContexts.Clear(); foreach (Automata.FinalItem item in state.Items) { Grammars.Terminal terminal = item as Grammars.Terminal; if (!currentContexts.Contains(terminal.Context)) { currentContexts.Add(terminal.Context); offset += 2; } } foreach (CharSpan key in state.Transitions) { if (key.End >= 256) { offset += 3; } } } foreach (Automata.DFAState state in dfa.States) { GenerateDataFor(writer, state); } writer.Close(); }
/// <summary> /// Generates the given state binary data /// </summary> /// <param name="writer">The output writer</param> /// <param name="state">The state to export</param> private void GenerateDataFor(BinaryWriter writer, Automata.DFAState state) { // build the transition data ushort[] cache = new ushort[256]; for (int i = 0; i != 256; i++) { cache[i] = Automaton.DEAD_STATE; } ushort cached = 0; // the number of cached transitions ushort slow = 0; // the number of non-cached transitions foreach (CharSpan span in state.Transitions) { if (span.Begin <= 255) { cached++; int end = span.End; if (end >= 256) { end = 255; slow++; } for (int i = span.Begin; i <= end; i++) { cache[i] = (ushort)state.GetChildBy(span).ID; } } else { slow++; } } // build the matched terminals data List <ushort> contextIDs = new List <ushort>(); List <ushort> matched = new List <ushort>(); foreach (Automata.FinalItem item in state.Items) { Grammars.Terminal terminal = item as Grammars.Terminal; if (!contextIDs.Contains((ushort)terminal.Context)) { // this is the first time this context is found in the current DFA state // this is the terminal with the most priority for this context contextIDs.Add((ushort)terminal.Context); matched.Add((ushort)terminals.IndexOf(terminal)); } } // write the number of matched terminals writer.Write((ushort)matched.Count); // write the total numer of transitions writer.Write((ushort)(slow + cached)); // write the number of non-cached transitions writer.Write(slow); // write the matched terminals for (int i = 0; i != matched.Count; i++) { writer.Write(contextIDs[i]); writer.Write(matched[i]); } // write the cached transitions for (int i = 0; i != 256; i++) { writer.Write(cache[i]); } // write the non-cached transitions List <CharSpan> keys = new List <CharSpan>(state.Transitions); keys.Sort(new System.Comparison <CharSpan>(CharSpan.CompareReverse)); foreach (CharSpan span in keys) { if (span.End <= 255) { break; // the rest of the transitions are in the cache } ushort begin = span.Begin; if (begin <= 255) { begin = 256; } writer.Write(begin); writer.Write(Convert.ToUInt16(span.End)); writer.Write((ushort)state.GetChildBy(span).ID); } }