//========================================================================================= /// <summary>Задать строку для нового разбора на токены.</summary> public void SetSource(string text) { this.CurrentState = null; this.ReturnPreviousToken = false; this.Errors.Clear(); this._Reader.SetSource(text); }
//========================================================================================= /// <summary>Получить очередной токен.</summary> public Token ReadNextToken() { if (this.ReturnPreviousToken && this.LastToken != null) { this.ReturnPreviousToken = false; return(this.LastToken); } ///Пропускаем все пробелы char cChar; do { cChar = this._Reader.ReadChar(); if (cChar == '\0') { return(null); } }while (char.IsWhiteSpace(cChar)); ///Становимся на начальное состояние this.CurrentState = this.Specification.StartState; ///Засекаем начало токена int iStart = this._Reader.Position - 1; var pointStart = this._Reader.PreviousPoint; while (true) { ///Ищем следующее состояние на основании текущего символа var oNewState = this.CurrentState.GetNextState(cChar); ///Если мы перешли в состоянии ошибки, генерим ошибку if (oNewState == this.Specification.FailState) { this.Errors.Add(this.CurrentState.GetExpectationToString()); } ///Если пора выходить if (oNewState == this.Specification.EndState) { var oToken = this.GetToken(iStart, pointStart, this._Reader.Position - 1, this._Reader.PreviousPoint); ///Возвращаемся на символ назад, чтобы в следующий раз начать с правильной позиции this._Reader.BackToChar(); return(oToken); } if (oNewState == null) { throw new NullReferenceException(this.CurrentState.Name); } this.CurrentState = oNewState; ///Читаем новый символ cChar = this._Reader.ReadChar(); if (cChar == '\0') { return(this.GetToken(iStart, pointStart, this._Reader.Position, this._Reader.Point)); } } }
//========================================================================================= /// <summary>Получить очередной токен.</summary> public Token ReadNextToken() { if (this.ReturnPreviousToken && this.LastToken != null) { this.ReturnPreviousToken = false; return this.LastToken; } ///Пропускаем все пробелы char cChar; do { cChar = this._Reader.ReadChar(); if (cChar == '\0') return null; } while (char.IsWhiteSpace(cChar)); ///Становимся на начальное состояние this.CurrentState = this.Specification.StartState; ///Засекаем начало токена int iStart = this._Reader.Position - 1; var pointStart = this._Reader.PreviousPoint; while (true) { ///Ищем следующее состояние на основании текущего символа var oNewState = this.CurrentState.GetNextState(cChar); ///Если мы перешли в состоянии ошибки, генерим ошибку if (oNewState == this.Specification.FailState) { this.Errors.Add(this.CurrentState.GetExpectationToString()); } ///Если пора выходить if (oNewState == this.Specification.EndState) { var oToken = this.GetToken(iStart, pointStart, this._Reader.Position - 1, this._Reader.PreviousPoint); ///Возвращаемся на символ назад, чтобы в следующий раз начать с правильной позиции this._Reader.BackToChar(); return oToken; } if (oNewState == null) throw new NullReferenceException(this.CurrentState.Name); this.CurrentState = oNewState; ///Читаем новый символ cChar = this._Reader.ReadChar(); if (cChar == '\0') return this.GetToken(iStart, pointStart, this._Reader.Position, this._Reader.Point); } }
//========================================================================================= public ScannerSpecification() { this.Literals = new List <Literal>(); this.States = new List <StateScannerState>(); this.StartState = new StateScannerState("<start>"); this.EndState = new StateScannerState("<end>"); this.FailState = new StateScannerState("<fail>"); this.States.Add(this.StartState); this.States.Add(this.EndState); this.States.Add(this.FailState); this.StartState.SetDefaultLink(this.FailState); this.FailState.SetDefaultLink(this.EndState); }
//========================================================================================= public ScannerSpecification() { this.Literals = new List<Literal>(); this.States = new List<StateScannerState>(); this.StartState = new StateScannerState("<start>"); this.EndState = new StateScannerState("<end>"); this.FailState = new StateScannerState("<fail>"); this.States.Add(this.StartState); this.States.Add(this.EndState); this.States.Add(this.FailState); this.StartState.SetDefaultLink(this.FailState); this.FailState.SetDefaultLink(this.EndState); }
//========================================================================================= /// <summary>Создать новое состояние или взять уже существующее, в которое мы переходим из указанного при получении на входе указанного символа.</summary> StateScannerState CreateOrGetState(StateScannerState from, Literal incoming, string stateName, string tokenName) { StateScannerState oState; if (from.Entries.TryGetValue(incoming, out oState)) { if (oState == this.EndState) { string sMsg = string.Format("Ambiguous link {0}->{1}: {2} or {3}.", from.Name, incoming.Name, from.ResultTokenName, tokenName); throw new ArgumentException(sMsg); } return(oState); } StateScannerState oNewState = new StateScannerState(stateName); from.AddLink(incoming, oNewState); this.States.Add(oNewState); oNewState.ResultTokenName = tokenName; return(oNewState); }
//========================================================================================= internal void AddBoundedToken(string name, string start, string end, string escape, int startlen, int endlen) { ///Находим начальные и конечные литералы Literal[] startLiterals = GetLiteralsFromString(start); Literal[] endLiterals = GetLiteralsFromString(end); ///Состояние, в котором будут приняты все символы между ограничителями StateScannerState oReccurentState; ///Создаем состояния для обработки входных ограничителей { StateScannerState oCurrentState = this.StartState; for (int i = 0; i < startLiterals.Length; i++) { string sStateName = string.Format("<{0}_start_{1}>", name, i); var oNewState = this.CreateOrGetState(oCurrentState, startLiterals[i], sStateName, name); if (oNewState.ElseState == null) { oNewState.SetDefaultLink(this.FailState); } oCurrentState = oNewState; } oReccurentState = oCurrentState; } ///Будем находиться в этом состоянии, пока не придет конечный ограничитель oReccurentState.SetDefaultLink(oReccurentState); ///Выходное состояние StateScannerState oEndState; ///Создаем состояния для обработки выходных ограничителей { ///Состояние, на которое нужно перейти в случае, если прерывается цепочка конечных ограничителей, ///но вместе с тем поступил первый ограничитель из этой цепочки. StateScannerState oFirstEndState = null; ///Номер такого состояния int iFirstEndState = 0; for (int i = 1; i < endLiterals.Length; i++) { if (endLiterals[i] == endLiterals[0]) { iFirstEndState = i; } else { break; } } StateScannerState oCurrentState = oReccurentState; for (int i = 0; i < endLiterals.Length; i++) { string sStateName = string.Format("<{0}_end_{1}>", name, i); var oNewState = this.CreateOrGetState(oCurrentState, endLiterals[i], sStateName, name); if (i == iFirstEndState) { if (string.IsNullOrEmpty(escape)) { oFirstEndState = oNewState; } } if (oFirstEndState != null) { oNewState.AddLink(endLiterals[0], oFirstEndState); } oNewState.SetDefaultLink(oReccurentState); oCurrentState = oNewState; } oEndState = oCurrentState; } oEndState.SetDefaultLink(this.EndState); oEndState.StartLimiterLength = startlen; oEndState.EndLimiterLength = endlen; var oEscapeLiteral = this.GetLiteralByName(escape); if (oEscapeLiteral != null) { StateScannerState oNextState = oReccurentState.GetNextState(oEscapeLiteral); if (oNextState == null || oNextState == oReccurentState.ElseState) { string sStateName = string.Format("<{0}_escape>", name); var oNewState = this.CreateOrGetState(oReccurentState, oEscapeLiteral, sStateName, name); oNewState.SetDefaultLink(oReccurentState); } else { oNextState.AddLink(startLiterals[0], oReccurentState); } } }
//========================================================================================= /// <summary>Переход по умолчанию, который выполняется, если не срабатывают условия других переходов.</summary> internal void SetDefaultLink(StateScannerState state) { this.ElseState = state; }
//========================================================================================= internal void AddLink(Literal literal, StateScannerState state) { this.Entries.Add(literal, state); }
//========================================================================================= /// <summary>Создать новое состояние или взять уже существующее, в которое мы переходим из указанного при получении на входе указанного символа.</summary> StateScannerState CreateOrGetState(StateScannerState from, Literal incoming, string stateName, string tokenName) { StateScannerState oState; if (from.Entries.TryGetValue(incoming, out oState)) { if (oState == this.EndState) { string sMsg = string.Format("Ambiguous link {0}->{1}: {2} or {3}.", from.Name, incoming.Name, from.ResultTokenName, tokenName); throw new ArgumentException(sMsg); } return oState; } StateScannerState oNewState = new StateScannerState(stateName); from.AddLink(incoming, oNewState); this.States.Add(oNewState); oNewState.ResultTokenName = tokenName; return oNewState; }