/// <summary> /// Gets the index of the terminal with the highest priority that is possible in the contexts /// </summary> /// <param name="state">The DFA state</param> /// <param name="provider">The current applicable contexts</param> /// <returns>The index of the terminal</returns> private int GetTerminalFor(int state, IContextProvider provider) { AutomatonState stateData = automaton.GetState(state); MatchedTerminal mt = stateData.GetTerminal(0); int id = symTerminals[mt.Index].ID; int currentResult = mt.Index; if (id == separatorID) { // the separator trumps all return(currentResult); } int currentPriority = provider.GetContextPriority(mt.Context, id); for (int i = 1; i != stateData.TerminalsCount; i++) { mt = stateData.GetTerminal(i); id = symTerminals[mt.Index].ID; if (id == separatorID) { // the separator trumps all return(mt.Index); } int priority = provider.GetContextPriority(mt.Context, id); if (currentPriority < 0 || (priority >= 0 && priority < currentPriority)) { currentResult = mt.Index; currentPriority = priority; } } return(currentResult); }
/// <summary> /// Inspects a head with a specified character ahead /// </summary> /// <param name="head">The head to inspect</param> /// <param name="offset">The current offset from the original index</param> /// <param name="current">The leading character in the input</param> private void Inspect(Head head, int offset, char current) { AutomatonState stateData = automaton.GetState(head.State); // is it a matching state if (stateData.TerminalsCount != 0 && stateData.GetTerminal(0).Index != separator) { OnMatchingHead(head, offset); } if (head.Distance >= maxDistance || stateData.IsDeadEnd) { // cannot stray further return; } // could be a straight match int target = stateData.GetTargetBy(current); if (target != Automaton.DEAD_STATE) { // it is! PushHead(head, target); } // could try a drop PushHead(head, head.State, offset); // lookup the transitions ExploreTransitions(head, stateData, offset, false); ExploreInsertions(head, offset, false, current); }
/// <summary> /// Explores a state transition /// </summary> /// <param name="head">The current head</param> /// <param name="stateData">The data of the DFA state</param> /// <param name="offset">The current offset from the original index</param> /// <param name="atEnd">Whether the current index is at the end of the input</param> private void ExploreTransitions(Head head, AutomatonState stateData, int offset, bool atEnd) { for (int i = 0; i != 256; i++) { int target = stateData.GetCachedTransition(i); if (target == Automaton.DEAD_STATE) { continue; } ExploreTransitionToTarget(head, target, offset, atEnd); } for (int i = 0; i != stateData.BulkTransitionsCount; i++) { ExploreTransitionToTarget(head, stateData.GetBulkTransition(i).Target, offset, atEnd); } }
/// <summary> /// Inspects a head while at the end of the input /// </summary> /// <param name="head">The head to inspect</param> /// <param name="offset">The current offset from the original index</param> private void InspectAtEnd(Head head, int offset) { AutomatonState stateData = automaton.GetState(head.State); // is it a matching state if (stateData.TerminalsCount != 0 && stateData.GetTerminal(0).Index != separator) { OnMatchingHead(head, offset); } if (head.Distance >= maxDistance || stateData.IsDeadEnd) { // cannot stray further return; } // lookup the transitions ExploreTransitions(head, stateData, offset, true); ExploreInsertions(head, offset, true, '\0'); }
/// <summary> /// Runs the lexer's DFA to match a terminal in the input ahead /// </summary> /// <param name="index">The current start index in the input text</param> /// <returns>The matching DFA state and length</returns> internal TokenMatch RunDFA(int index) { if (text.IsEnd(index)) { // At the end of input // The only terminal matched at state index 0 is $ return(new TokenMatch(0, 0)); } TokenMatch result = new TokenMatch(0); int state = 0; int i = index; while (state != Automaton.DEAD_STATE) { AutomatonState stateData = automaton.GetState(state); // Is this state a matching state ? if (stateData.TerminalsCount != 0) { result = new TokenMatch(state, i - index); } // No further transition => exit if (stateData.IsDeadEnd) { break; } // At the end of the buffer if (text.IsEnd(i)) { break; } char current = text.GetValue(i); i++; // Try to find a transition from this state with the read character state = stateData.GetTargetBy(current); } return(result); }
/// <summary> /// Explores an insertion /// </summary> /// <param name="head">The head to inspect</param> /// <param name="offset">The current offset from the original index</param> /// <param name="atEnd">Whether the current index is at the end of the input</param> /// <param name="current">The leading character in the input</param> /// <param name="state">The DFA state for the insertion</param> /// <param name="distance">The distance associated to this insertion</param> private void ExploreInsertion(Head head, int offset, bool atEnd, char current, int state, int distance) { AutomatonState stateData = automaton.GetState(state); if (stateData.TerminalsCount != 0 && stateData.GetTerminal(0).Index != separator) { OnMatchingInsertion(head, offset, state, distance); } if (!atEnd) { int target = stateData.GetTargetBy(current); if (target != Automaton.DEAD_STATE) { PushHead(head, target, offset, distance); } } if (distance >= maxDistance) { return; } // continue insertion ExploreTransitions(head, stateData, offset, true); }