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); }
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]; } }
public bool TransitionExists(ParserState transitionFrom, GrammarSymbol symbol) { return _stateTransitions.ContainsKey(transitionFrom) && _stateTransitions[transitionFrom].ContainsKey(symbol); }
/// <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]; } }
public override bool Equals(GrammarSymbol other) { return other is Start; }
private Core.GrammarElements.Production GetAugmentedProduction(NonTerminal start, GrammarSymbol root, GrammarSymbol endOfStream) { return new Core.GrammarElements.Production(_productionId++, start, new[] { root, endOfStream }); }
public override bool Equals(GrammarSymbol other) { return other is EndOfStream; }
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)); }
/// <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); }
/// <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; }
/// <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; }
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; }