| 55 | 1 using Implab; | 
|  | 2 using System; | 
|  | 3 using System.Collections.Generic; | 
|  | 4 using System.Linq; | 
|  | 5 using System.Text; | 
|  | 6 using System.Threading.Tasks; | 
|  | 7 | 
|  | 8 namespace Implab.Parsing { | 
|  | 9     /// <summary> | 
|  | 10     /// Базовый класс для разбора потока входных символов на токены. | 
|  | 11     /// </summary> | 
|  | 12     /// <remarks> | 
|  | 13     /// Сканнер имеет внутри буффер с симолами входного текста, по которому перемещаются два | 
|  | 14     /// указателя, начала и конца токена, при перемещении искользуется ДКА для определения | 
|  | 15     /// конца токена и допустимости текущего символа. | 
|  | 16     /// </remarks> | 
|  | 17     public class Scanner { | 
|  | 18         struct ScannerConfig { | 
|  | 19             public DFAStateDescriptior[] states; | 
|  | 20             public int[] alphabetMap; | 
|  | 21         } | 
|  | 22 | 
|  | 23         Stack<ScannerConfig> m_defs = new Stack<ScannerConfig>(); | 
|  | 24 | 
|  | 25         DFAStateDescriptior[] m_states; | 
|  | 26         int[] m_alphabetMap; | 
|  | 27 | 
|  | 28         protected DFAStateDescriptior m_currentState; | 
|  | 29         int m_previewCode; | 
|  | 30 | 
|  | 31         protected int m_tokenLen = 0; | 
|  | 32         protected int m_tokenOffset; | 
|  | 33 | 
|  | 34         protected char[] m_buffer; | 
|  | 35         protected int m_bufferSize; | 
|  | 36         protected int m_pointer; | 
|  | 37 | 
|  | 38         public Scanner(CDFADefinition definition, string text) { | 
|  | 39             Safe.ArgumentNotNull(definition, "definition"); | 
|  | 40             Safe.ArgumentNotEmpty(text, "text"); | 
|  | 41 | 
|  | 42             m_states = definition.States; | 
|  | 43             m_alphabetMap = definition.Alphabet.GetTranslationMap(); | 
|  | 44 | 
|  | 45             Feed(text.ToCharArray()); | 
|  | 46         } | 
|  | 47 | 
|  | 48         public Scanner(CDFADefinition definition) { | 
|  | 49             Safe.ArgumentNotNull(definition, "definition"); | 
|  | 50 | 
|  | 51             m_states = definition.States; | 
|  | 52             m_alphabetMap = definition.Alphabet.GetTranslationMap(); | 
|  | 53 | 
|  | 54             Feed(new char[0]); | 
|  | 55         } | 
|  | 56 | 
|  | 57         /// <summary> | 
|  | 58         /// Заполняет входными данными буффер. | 
|  | 59         /// </summary> | 
|  | 60         /// <param name="data">Данные для обработки.</param> | 
|  | 61         /// <remarks>Копирование данных не происходит, переданный массив используется в | 
|  | 62         /// качестве входного буффера.</remarks> | 
|  | 63         public void Feed(char[] data) { | 
|  | 64             Safe.ArgumentNotNull(data, "data"); | 
|  | 65 | 
|  | 66             Feed(data, data.Length); | 
|  | 67         } | 
|  | 68 | 
|  | 69         /// <summary> | 
|  | 70         /// Заполняет буффур чтения входными данными. | 
|  | 71         /// </summary> | 
|  | 72         /// <param name="data">Данные для обработки.</param> | 
|  | 73         /// <param name="length">Длина данных для обработки.</param> | 
|  | 74         /// <remarks>Копирование данных не происходит, переданный массив используется в | 
|  | 75         /// качестве входного буффера.</remarks> | 
|  | 76         public void Feed(char[] data, int length) { | 
|  | 77             Safe.ArgumentNotNull(data, "data"); | 
|  | 78             Safe.ArgumentInRange(length, 0, data.Length, "length"); | 
|  | 79 | 
|  | 80             m_pointer = -1; | 
|  | 81             m_buffer = data; | 
|  | 82             m_bufferSize = length; | 
|  | 83             Shift(); | 
|  | 84         } | 
|  | 85 | 
|  | 86         /// <summary> | 
|  | 87         /// Получает текущий токен в виде строки. | 
|  | 88         /// </summary> | 
|  | 89         /// <returns></returns> | 
|  | 90         public string GetTokenValue() { | 
|  | 91             return new String(m_buffer, m_tokenOffset, m_tokenLen); | 
|  | 92         } | 
|  | 93 | 
|  | 94         /// <summary> | 
|  | 95         /// Метки текущего токена, которые были назначены в регулярном выражении. | 
|  | 96         /// </summary> | 
|  | 97         public int[] TokenTags { | 
|  | 98             get { | 
|  | 99                 return m_currentState.tag; | 
|  | 100             } | 
|  | 101         } | 
|  | 102 | 
|  | 103         /// <summary> | 
|  | 104         /// Читает следующий токен, при этом <see cref="m_tokenOffset"/> указывает на начало токена, | 
|  | 105         /// <see cref="m_tokenLen"/> на длину токена, <see cref="m_buffer"/> - массив символов, в | 
|  | 106         /// котором находится токен. | 
|  | 107         /// </summary> | 
|  | 108         /// <returns><c>false</c> - достигнут конец данных, токен не прочитан.</returns> | 
|  | 109         protected bool ReadTokenInternal() { | 
|  | 110             if (m_pointer >= m_bufferSize) | 
|  | 111                 return false; | 
|  | 112 | 
|  | 113             m_currentState = m_states[CDFADefinition.INITIAL_STATE]; | 
|  | 114             m_tokenLen = 0; | 
|  | 115             m_tokenOffset = m_pointer; | 
|  | 116             int nextState = CDFADefinition.UNREACHEBLE_STATE; | 
|  | 117             do { | 
|  | 118                 nextState = m_currentState.transitions[m_previewCode]; | 
|  | 119                 if (nextState == CDFADefinition.UNREACHEBLE_STATE) { | 
|  | 120                     if (m_currentState.final) | 
|  | 121                         return true; | 
|  | 122                     else | 
|  | 123                         throw new ParserException( | 
|  | 124                             String.Format( | 
|  | 125                                 "Unexpected symbol '{0}', at pos {1}", | 
|  | 126                                 m_buffer[m_pointer], | 
|  | 127                                 Position | 
|  | 128                             ) | 
|  | 129                         ); | 
|  | 130                 } else { | 
|  | 131                     m_currentState = m_states[nextState]; | 
|  | 132                     m_tokenLen++; | 
|  | 133                 } | 
|  | 134 | 
|  | 135             } while (Shift()); | 
|  | 136 | 
|  | 137             // END OF DATA | 
|  | 138             if (!m_currentState.final) | 
|  | 139                 throw new ParserException("Unexpected end of data"); | 
|  | 140 | 
|  | 141             return true; | 
|  | 142         } | 
|  | 143 | 
|  | 144 | 
|  | 145         bool Shift() { | 
|  | 146             m_pointer++; | 
|  | 147 | 
|  | 148             if (m_pointer >= m_bufferSize) { | 
|  | 149                 return ReadNextChunk(); | 
|  | 150             } | 
|  | 151 | 
|  | 152             m_previewCode = m_alphabetMap[m_buffer[m_pointer]]; | 
|  | 153 | 
|  | 154             return true; | 
|  | 155         } | 
|  | 156 | 
|  | 157         /// <summary> | 
|  | 158         /// Вызывается по достижению конца входного буффера для получения | 
|  | 159         /// новых данных. | 
|  | 160         /// </summary> | 
|  | 161         /// <returns><c>true</c> - новые двнные получены, можно продолжать обработку.</returns> | 
|  | 162         protected virtual bool ReadNextChunk() { | 
|  | 163             return false; | 
|  | 164         } | 
|  | 165 | 
|  | 166         /// <summary> | 
|  | 167         /// Позиция сканнера во входном буфере | 
|  | 168         /// </summary> | 
|  | 169         public int Position { | 
|  | 170             get { | 
|  | 171                 return m_pointer + 1; | 
|  | 172             } | 
|  | 173         } | 
|  | 174 | 
|  | 175         /// <summary> | 
|  | 176         /// Преключает внутренний ДКА на указанный, позволяет реализовать подобие захватывающей | 
|  | 177         /// группировки. | 
|  | 178         /// </summary> | 
|  | 179         /// <param name="states">Таблица состояний нового ДКА</param> | 
|  | 180         /// <param name="alphabet">Таблица входных символов для нового ДКА</param> | 
|  | 181         protected void Switch(DFAStateDescriptior[] states, int[] alphabet) { | 
|  | 182             Safe.ArgumentNotNull(states, "dfa"); | 
|  | 183 | 
|  | 184             m_defs.Push(new ScannerConfig { | 
|  | 185                 states = m_states, | 
|  | 186                 alphabetMap = m_alphabetMap | 
|  | 187             }); | 
|  | 188 | 
|  | 189             m_states = states; | 
|  | 190             m_alphabetMap = alphabet; | 
|  | 191 | 
|  | 192             m_previewCode = m_alphabetMap[m_buffer[m_pointer]]; | 
|  | 193         } | 
|  | 194 | 
|  | 195         /// <summary> | 
|  | 196         /// Восстанавливает предыдущей ДКА сканнера. | 
|  | 197         /// </summary> | 
|  | 198         protected void Restore() { | 
|  | 199             if (m_defs.Count == 0) | 
|  | 200                 throw new InvalidOperationException(); | 
|  | 201             var prev = m_defs.Pop(); | 
|  | 202             m_states = prev.states; | 
|  | 203             m_alphabetMap = prev.alphabetMap; | 
|  | 204             m_previewCode = m_alphabetMap[m_buffer[m_pointer]]; | 
|  | 205         } | 
|  | 206     } | 
|  | 207 } |