Ejemplo n.º 1
0
 public void AddTransition(ParserState transitionFrom, GrammarSymbol symbol, ParserState transitionTo)
 {
     if(!_stateTransitions.ContainsKey(transitionFrom))
         _stateTransitions.Add(transitionFrom, new Dictionary<GrammarSymbol,ParserState>());
     if (_stateTransitions[transitionFrom].ContainsKey(symbol))
         throw new Exception("State conflict. Trying to add a transition for a state when one already exists for the specified grammar symbol.");
     _stateTransitions[transitionFrom][symbol] = transitionTo;
     _states.Add(transitionFrom);
     _states.Add(transitionTo);
 }
Ejemplo n.º 2
0
 public TransitionAction this[ParserState state, GrammarSymbol symbol]
 {
     get
     {
         if(!_table.ContainsKey(state))
             throw new InvalidOperationException("The given state is unknown for this transition table.");
         var tableEntry = _table[state];
         if (!tableEntry.ContainsKey(symbol))
             throw new InvalidOperationException("There is no transition from the given state under the given input.");
         return tableEntry[symbol];
     }
 }
Ejemplo n.º 3
0
 public bool TransitionExists(ParserState transitionFrom, GrammarSymbol symbol)
 {
     return _stateTransitions.ContainsKey(transitionFrom) && _stateTransitions[transitionFrom].ContainsKey(symbol);
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Describes the transition from the given state to another state under the given input symbol.
 /// </summary>
 public ParserState this[ParserState transitionFrom, GrammarSymbol symbol]
 {
     get { return _stateTransitions[transitionFrom][symbol]; }
 }
Ejemplo n.º 5
0
 public override bool Equals(GrammarSymbol other)
 {
     return other is Start;
 }
Ejemplo n.º 6
0
 private Core.GrammarElements.Production GetAugmentedProduction(NonTerminal start, GrammarSymbol root, GrammarSymbol endOfStream)
 {
     return new Core.GrammarElements.Production(_productionId++,
                                                start,
                                                new[]
                                                {
                                                    root, endOfStream
                                                });
 }
Ejemplo n.º 7
0
 public override bool Equals(GrammarSymbol other)
 {
     return other is EndOfStream;
 }
Ejemplo n.º 8
0
        public Grammar GetGrammar()
        {
            string fileContents = File.ReadAllText(_fileName);

            var tokenStream = Lexer.Run(fileContents);

            var parser = new Parser();

            var parseTree = parser.Parse(tokenStream);

            var grammarCreator = new GrammarTreeVisitor();

            parseTree.AcceptVisitor(grammarCreator);

            var isValid = ValidateGrammar(grammarCreator.Tokens, grammarCreator.Productions);

            var terminals = (from symbolName in grammarCreator.Tokens
                             select new Terminal(_symbolId++, symbolName))
                             .ToDictionary(terminal => terminal.Name);

            var nonTerminals = grammarCreator.Productions
                                .Select(production => production.ProductionHead)
                                .Distinct()
                                .Select(symbolName => new NonTerminal(_symbolId++, symbolName))
                                .ToDictionary(nonTerminal => nonTerminal.Name);

            var productions = new List<Core.GrammarElements.Production>();

            foreach (var nonTerminal in nonTerminals.Keys)
            {
                foreach (var production in grammarCreator.Productions.Where(x => x.ProductionHead == nonTerminal))
                {
                    var tail = new GrammarSymbol[production.ProductionTail.Count];
                    for (int i = 0; i < tail.Length; i++)
                    {
                        var productionToken = production.ProductionTail[i];
                        if (terminals.ContainsKey(productionToken))
                        {
                            tail[i] = terminals[productionToken];
                        }
                        else if(nonTerminals.ContainsKey(productionToken))
                        {
                            tail[i] = nonTerminals[productionToken];
                        }
                        else
                        {
                            throw new Exception("Unknown production head.");
                        }
                    }
                    productions.Add(new Core.GrammarElements.Production(_productionId++, nonTerminals[nonTerminal], tail));
                }
            }

            var endOfStream = EndOfStream.Instance;
            terminals.Add(endOfStream.Name, endOfStream);

            var startAugmentedSymbol = new NonTerminal(_symbolId++, AugmentedStart);
            nonTerminals.Add(AugmentedStart, startAugmentedSymbol);

            var root = GetGrammarRoot(productions);
            var augmentedProduction = GetAugmentedProduction(startAugmentedSymbol, root, endOfStream);

            productions.Add(augmentedProduction);

            return new Grammar(productions, terminals.Values.Cast<GrammarSymbol>().Concat(nonTerminals.Values).ToList(), new Item(augmentedProduction));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Returns the set of items that can be transitioned to from inputItems
        /// under input <paramref name="symbol"/>.
        /// Refer Dragon Book pg 246
        /// </summary>
        /// <param name="inputItems"></param>
        /// <param name="symbol"></param>
        /// <returns></returns>
        private IList<Item> Goto(IEnumerable<Item> inputItems, GrammarSymbol symbol)
        {
            if (inputItems == null)
                throw new ArgumentNullException("inputItems");
            if (symbol == null)
                throw new ArgumentNullException("symbol");

            var items = inputItems.Where(inputItem => inputItem.HasNextToken && inputItem.NextToken == symbol);
            items = items.Select(inputItem => inputItem.AdvanceDot());
            return GetClosure(items);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Returns FIRST(X) which is defined as the set of terminals that
        /// can start a string of symbols derived from X.
        /// </summary>
        /// <param name="symbol"></param>
        /// <returns></returns>
        private IEnumerable<Terminal> FirstSet(GrammarSymbol symbol)
        {
            if (symbol == null)
                throw new ArgumentNullException("symbol");

            //have we already calculated the FIRST set of this symbol?
            if (_firstSetCache.ContainsKey(symbol))
                return _firstSetCache[symbol];

            //The FIRST set of a terminal is itself.
            if (symbol is Terminal)
                return new List<Terminal> { symbol as Terminal };

            var result = new HashSet<Terminal>();

            //Get the starting symbol of a production where:
            //  The production has a valid tail (doesn't derive to an empty string)
            //  The head of the production is the symbol we are interested in
            //  The production isn't left recursive (so we don't get infinite recursion)
            var productionStartValues =
                Productions.Where(prod => prod.Length > 0 && prod.Head == symbol && prod[0] != prod.Head)
                .Select(prod => prod[0]);

            foreach (var value in productionStartValues)
            {
                if (value is Terminal)
                    result.Add(value as Terminal);
                else
                    //Recursively get the FIRST set of the non-terminals
                    result.UnionWith(FirstSet(value));
            }

            var resultList = result.ToList();
            _firstSetCache.Add(symbol, resultList);
            return resultList;
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Returns FOLLOW(X) which is defined as the set of terminals that
        /// can appear immediately after some string of symbols derived from X.
        /// </summary>
        /// <remarks>
        /// Cannot calculate the FOLLOW set for a Terminal.
        /// </remarks>
        /// <param name="nonTerminal"></param>
        /// <returns></returns>
        public IList<GrammarSymbol> FollowSet(GrammarSymbol nonTerminal)
        {
            if (nonTerminal == null)
                throw new ArgumentNullException("nonTerminal");

            if (_followSetCache.ContainsKey(nonTerminal))
                return _followSetCache[nonTerminal];

            if (nonTerminal is Terminal)
                throw new ArgumentException("Cannot calculate the FOLLOW set for a Terminal.", "nonTerminal");

            var result = new HashSet<GrammarSymbol>();

            foreach (var production in Productions)
            {
                for (int i = 0; i < production.Length; i++)
                {
                    //Find the position of the nonterminal in the production
                    if (production[i] == nonTerminal)
                    {
                        //If the index of the nonterminal is at the end of the
                        //  production's tail, then we add the FOLLOW set
                        //  of the production's head to the result.
                        //Otherwise, we find the FIRST set of the following
                        //  element in the production, and add it to the FOLLOW set.
                        if (i == production.Length - 1)
                        {
                            result.UnionWith(FollowSet(production.Head));
                        }
                        else
                        {
                            result.UnionWith(FirstSet(production[i + 1]));
                        }
                    }
                }
            }
            var resultList = result.ToList();
            _followSetCache.Add(nonTerminal, resultList);
            return resultList;
        }
Ejemplo n.º 12
0
        private CodeMemberMethod GetOverrideActionMethod(GrammarSymbol currToken, TransitionTable table)
        {
            var result = new CodeMemberMethod
            {
                Name = Constants.TerminalActionMethodName,
                Attributes = MemberAttributes.Public | MemberAttributes.Override,
                ReturnType = new CodeTypeReference(Constants.ActionEnumName)
            };
            result.Parameters.Add(new CodeParameterDeclarationExpression(Constants.StateStackType, Constants.StateStackVarName));
            result.Parameters.Add(new CodeParameterDeclarationExpression(Constants.ParseStackType, Constants.ParseStackVarName));

            var states = new CodeArgumentReferenceExpression(Constants.StateStackVarName);
            var parseStack = new CodeArgumentReferenceExpression(Constants.ParseStackVarName);

            result.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference(typeof(int)), "currentState", new CodeMethodInvokeExpression(states, "Peek")));

            foreach (var state in table.StateMap.States)
            {
                var ifState = new CodeConditionStatement(new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("currentState"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(state.StateId)));
                var action = table[state, currToken];
                if (action.Action == ParserAction.Shift)
                {
                    ifState.TrueStatements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(states, "Push"), new CodePrimitiveExpression(action.NextState.StateId)));
                    ifState.TrueStatements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(parseStack, "Push"), new CodeThisReferenceExpression()));
                    ifState.TrueStatements.Add(new CodeMethodReturnStatement(FieldReference(new CodeTypeReferenceExpression(Constants.ActionEnumName), "ShiftContinue")));
                }
                if (action.Action == ParserAction.Reduce)
                {
                    ifState.TrueStatements.Add(new CodeMethodInvokeExpression(parseStack, "Push", new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(GetClassName(action.ReduceByProduction)), Constants.ReduceByMethodName), parseStack)));
                    for (int i = 0; i < action.ReduceByProduction.Length; i++)
                    {
                        ifState.TrueStatements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(states, "Pop")));
                    }
                    ifState.TrueStatements.Add(new CodeMethodReturnStatement(FieldReference(new CodeTypeReferenceExpression(Constants.ActionEnumName), "ReduceContinue")));
                }
                if (action.Action == ParserAction.Accept)
                {
                    ifState.TrueStatements.Add(new CodeMethodReturnStatement(FieldReference(new CodeTypeReferenceExpression(Constants.ActionEnumName), "Accept")));
                }
                if (action.Action == ParserAction.Error)
                {
                    ifState.TrueStatements.Add(new CodeMethodReturnStatement(FieldReference(new CodeTypeReferenceExpression(Constants.ActionEnumName), "Error")));
                }
                result.Statements.Add(ifState);
            }
            result.Statements.Add(new CodeMethodReturnStatement(FieldReference(new CodeTypeReferenceExpression(Constants.ActionEnumName), "Error")));
            return result;
        }