/// This method implements the DFA algorithm and returns a token /// to the LALR state machine. private Token RetrieveToken() { Token result; int currentPos = 0; int lastAcceptState = -1; int lastAcceptPos = -1; FAState currentState = m_DfaStates[m_initDfaState]; try { while (true) { // This code searches all the branches of the current DFA state for the next // character in the input LookaheadStream. If found the target state is returned. // The InStr() function searches the string pCharacterSetTable.Member(CharSetIndex) // starting at position 1 for ch. The pCompareMode variable determines whether // the search is case sensitive. int target = -1; char ch = FixCase(m_source.LookAhead(currentPos)); foreach (FAEdge edge in currentState.Edges) { String chars = edge.Characters; if (chars.IndexOf(ch) != -1) { target = edge.TargetIndex; break; } } // This block-if statement checks whether an edge was found from the current state. // If so, the state and current position advance. Otherwise it is time to exit the main loop // and report the token found (if there was it fact one). If the LastAcceptState is -1, // then we never found a match and the Error Token is created. Otherwise, a new token // is created using the Symbol in the Accept State and all the characters that // comprise it. if (target != -1) { // This code checks whether the target state accepts a token. If so, it sets the // appropiate variables so when the algorithm is done, it can return the proper // token and number of characters. if (m_DfaStates[target].AcceptSymbol != -1) { lastAcceptState = target; lastAcceptPos = currentPos; } currentState = m_DfaStates[target]; currentPos++; } else { if (lastAcceptState == -1) { result = new Token(m_errorSymbol); result.Data = m_source.Read(1); } else { Symbol symbol = m_symbols[m_DfaStates[lastAcceptState].AcceptSymbol]; result = new Token(symbol); result.Data = m_source.Read(lastAcceptPos + 1); } break; } } } catch (EndOfStreamException) { result = new Token(m_endSymbol); result.Data = ""; } UpdateLineNumber((String)result.Data); return result; }
/// This function analyzes a token and either: /// 1. Makes a SINGLE reduction and pushes a complete Reduction object on the stack /// 2. Accepts the token and shifts /// 3. Errors and places the expected symbol indexes in the Tokens list /// The Token is assumed to be valid and WILL be checked private ParseResult ParseToken(Token p_token) { ParseResult result = ParseResult.InternalError; LRActionTable table = m_LalrTables[m_LalrState]; LRAction action = table.GetActionForSymbol(p_token.TableIndex); if (action != null) { m_haveReduction = false; m_outputTokens.Clear(); switch (action.Action) { case Action.Accept: m_haveReduction = true; result = ParseResult.Accept; break; case Action.Shift: p_token.State = m_LalrState = action.Value; m_tempStack.PushToken(p_token); result = ParseResult.Shift; break; case Action.Reduce: result = Reduce(m_rules[action.Value]); break; } } else { // syntax error - fill expected tokens. m_outputTokens.Clear(); foreach (LRAction a in table.Members) { SymbolType kind = a.Symbol.Kind; if (kind == SymbolType.Terminal || kind == SymbolType.End) m_outputTokens.PushToken(new Token(a.Symbol)); } result = ParseResult.SyntaxError; } return result; }
/// <summary>Produces a reduction.</summary> /// <remarks>Removes as many tokens as members in the rule and pushes a /// non-terminal token.</remarks> private ParseResult Reduce(Rule p_rule) { ParseResult result; Token head; if (m_trimReductions && p_rule.ContainsOneNonTerminal) { // The current rule only consists of a single nonterminal and can be trimmed from the // parse tree. Usually we create a new Reduction, assign it to the Data property // of Head and push it on the stack. However, in this case, the Data property of the // Head will be assigned the Data property of the reduced token (i.e. the only one // on the stack). In this case, to save code, the value popped of the stack is changed // into the head. head = m_tempStack.PopToken(); head.SetParent(p_rule.RuleNonTerminal); result = ParseResult.ReduceEliminated; } else { Reduction reduction = new Reduction(); reduction.ParentRule = p_rule; m_tempStack.PopTokensInto(reduction, p_rule.SymbolCount); head = new Token(); head.Data = reduction; head.SetParent(p_rule.RuleNonTerminal); m_haveReduction = true; result = ParseResult.ReduceNormal; } int index = m_tempStack.PeekToken().State; LRAction action = m_LalrTables[index].GetActionForSymbol(p_rule.RuleNonTerminal.TableIndex); if (action != null) { head.State = m_LalrState = action.Value;; m_tempStack.PushToken(head); } else throw new ParserException("Action for LALR state is null"); return result; }
/// Returns true if the specified token is a CommentLine or CommentStart-symbol. private bool CommentToken(Token p_token) { return (p_token.Kind == SymbolType.CommentLine) || (p_token.Kind == SymbolType.CommentStart); }
private void PrepareToParse() { Token token = new Token(); token.State = m_initLalrState; token.SetParent(m_symbols[m_startSymbol]); m_tempStack.PushToken(token); }
/* public methods */ /// Pushes the specified token onto the internal input queue. /// It will be the next token analyzed by the parsing engine. public void PushInputToken(Token p_token) { m_inputTokens.PushToken(p_token); }
/// Pushes the specified token on the stack. public void PushToken(Token p_token) { m_items.Add(p_token); }
/* internal methods */ /// internal void AddToken(Token p_token) { m_tokens.Add(p_token); }