예제 #1
0
        /// <summary>
        /// Applies the suppled production rule starting at token index
        /// This will recursively call further production rules
        /// </summary>
        /// <returns><c>true</c>, if rule was applied, <c>false</c> otherwise.</returns>
        /// <param name="r">The red component.</param>
        /// <param name="tokenIndex">Token index.</param>
        /// <param name="indent">Indent.</param>
        bool ApplyRule(ProductionRule r, ref int tokenIndex, int indent = 0)
        {
            Log("Applying " + r.ToString() + " to " + string.Join(", ", _tokens.GetRange(tokenIndex, _tokens.Count - tokenIndex).Select(t => $"{t.TokenType.Name} ({t.Value})")), indent);
            _rulesStack.Push(r.Name);

            var incomingTokenIndex = tokenIndex;

            // In order to pass this rule one of the RuleParts must evaluate
            bool evaluatedRuleSuccessfully = false;
            ProductionRulePart successfullyEvaluatedRulePart = null;

            for (int i = 0; i < r.Rhs.Count; i++)
            {
                // Take a copy of tokens.
                if (ApplyRulePart(r.Rhs[i], ref tokenIndex, indent))
                {
                    // We have passed - so can break out.
                    // Otherwise, try the next rule part
                    evaluatedRuleSuccessfully     = true;
                    successfullyEvaluatedRulePart = r.Rhs[i];
                    break;
                }
            }
            if (evaluatedRuleSuccessfully)
            {
                var nodePosition = GetRuleNodePosition(tokenIndex, incomingTokenIndex);
                _treeNodeStack.Push(
                    new AbstractSyntaxRuleNode(
                        r,
                        r.Rhs.IndexOf(successfullyEvaluatedRulePart),
                        nodePosition,
                        _source.Substring(nodePosition.Index, nodePosition.Length)
                        )
                    );
            }
            else
            {
                // restore the index - we need to try a different rule
                tokenIndex = incomingTokenIndex;
            }
            _rulesStack.Pop();
            return(evaluatedRuleSuccessfully);
        }
예제 #2
0
        /// <summary>
        /// Applies the rule part starting at the given token index
        /// </summary>
        /// <returns><c>true</c>, if rule part was applyed, <c>false</c> otherwise.</returns>
        /// <param name="rulePart">Rule part.</param>
        /// <param name="tokenIndex">Token index.</param>
        /// <param name="indent">Indent.</param>
        bool ApplyRulePart(ProductionRulePart rulePart, ref int tokenIndex, int indent)
        {
            Log("Testing " + rulePart.ToString() + " " + string.Join(", ", _tokens.GetRange(tokenIndex, _tokens.Count - tokenIndex).Select(t => $"{t.TokenType.Name} ({t.Value})")), indent);

            var incomingTokenIndex = tokenIndex;

            foreach (var target in rulePart)
            {
                // Get the current token at the start of each loop - index may have changed.
                var currentToken = GetToken(tokenIndex);

                if (IsTerminal(target))
                {
                    var    symbolParts  = target.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    string terminalName = symbolParts.First();
                    string value        = symbolParts.Length != 2 ?
                                          string.Empty :
                                          symbolParts.Last().Trim('\'');
                    if (currentToken != null && currentToken.TokenType.Name == terminalName)
                    {
                        Log($"- Matched  {target} to Token {currentToken.TokenType.Name} {currentToken.Value}", indent);

                        // TODO - These could be orphaned if this target succeeds but others fail
                        // Not a problem but consider tidying up?
                        _treeNodeStack.Push(
                            new AbstractSyntaxTerminalNode(
                                currentToken.TokenType,
                                currentToken.Value,
                                currentToken.Position,
                                _source.Substring(currentToken.Position.Index, currentToken.Position.Length)
                                )
                            );
                        tokenIndex++;
                    }
                    else if (currentToken != null)
                    {
                        Log($"- Failed Match Expected {target} Token {GetToken(tokenIndex).TokenType.Name} {GetToken(tokenIndex).Value}", indent);
                        // Since this was the wrong terminal then the RulePart has failed.
                        var rulesList = _rulesStack.ToList();
                        rulesList.Reverse();
                        _errors.Add(new ParserError($"Expected {target}.  Encountered {GetToken(tokenIndex).TokenType.Name} {GetToken(tokenIndex).Value} at {GetToken(tokenIndex).Position}", tokenIndex, rulesList));
                        tokenIndex = incomingTokenIndex;
                        return(false);
                    }
                    else
                    {
                        Log($"- Failed Match Expected {target} Found nothing", indent);
                        // Since this was the wrong terminal then the RulePart has failed.
                        var rulesList = _rulesStack.ToList();
                        rulesList.Reverse();
                        _errors.Add(new ParserError($"Expected {target}.  Encountered EOF", tokenIndex, rulesList));
                        tokenIndex = incomingTokenIndex;
                        return(false);
                    }
                }
                else
                {
                    var nextRule = _grammar.ProductionRules.Where(cr => cr.Name == target).First();

                    if (!ApplyRule(nextRule, ref tokenIndex, indent + 1))
                    {
                        // Hmm, this rule faile - reset token index
                        tokenIndex = incomingTokenIndex;
                        return(false);
                    }
                    else
                    {
                        // This rule succeeded - but there may be more - we should use the current token index returned from this moving forwards
                    }
                }
            }
            // If we've got here then this rule passed
            return(true);
        }