/// <summary> /// Parses the input and returns the produced AST /// </summary> /// <returns>AST produced by the parser representing the input, or null if unrecoverable errors were encountered</returns> public override ParseResult Parse() { reductions = new Queue <Reduction>(); shifts = new Queue <Shift>(); int Ui = gss.CreateGeneration(); int v0 = gss.CreateNode(0); nextToken = lexer.GetNextToken(this); // bootstrap the shifts and reductions queues int count = parserAutomaton.GetActionsCount(0, nextToken.TerminalID); for (int i = 0; i != count; i++) { LRAction action = parserAutomaton.GetAction(0, nextToken.TerminalID, i); if (action.Code == LRActionCode.Shift) { shifts.Enqueue(new Shift(v0, action.Data)); } else if (action.Code == LRActionCode.Reduce) { reductions.Enqueue(new Reduction(v0, parserAutomaton.GetProduction(action.Data), SPPF.EPSILON)); } } while (nextToken.TerminalID != Symbol.SID_EPSILON) // Wait for ε token { // the stem length (initial number of nodes in the generation before reductions) int stem = gss.GetGeneration(Ui).Count; // apply all reduction actions Reducer(Ui); // no scheduled shift actions? if (shifts.Count == 0) { // the next token was not expected OnUnexpectedToken(stem); return(new ParseResult(new ROList <ParseError>(allErrors), lexer.Input)); } // look for the next next-token Lexer.TokenKernel oldtoken = nextToken; nextToken = lexer.GetNextToken(this); // apply the scheduled shift actions Ui = Shifter(oldtoken); } GSSGeneration genData = gss.GetGeneration(Ui); for (int i = genData.Start; i != genData.Start + genData.Count; i++) { int state = gss.GetRepresentedState(i); if (parserAutomaton.IsAcceptingState(state)) { // Has reduction _Axiom_ -> axiom $ . on ε GSSPath[] paths = gss.GetPaths(i, 2, out count); return(new ParseResult(new ROList <ParseError>(allErrors), lexer.Input, sppf.GetTree(paths[0][1]))); } } // At end of input but was still waiting for tokens return(new ParseResult(new ROList <ParseError>(allErrors), lexer.Input)); }
/// <summary> /// Creates a new edge in the GSS /// </summary> /// <param name="from">The edge's starting node</param> /// <param name="to">The edge's target node</param> /// <param name="label">The edge's label</param> public void CreateEdge(int from, int to, int label) { edges.Add(new GSSEdge(from, to, label)); GSSGeneration data = edgeGenerations[generation]; data.Count++; edgeGenerations[generation] = data; }
/// <summary> /// Prints this stack with the specified writer /// </summary> /// <param name="writer">A text writer</param> public void PrintTo(TextWriter writer) { // list of all nodes having at least one child List <int> linked = new List <int>(); for (int i = generation; i != -1; i--) { writer.WriteLine("--- generation {0} ---", i); // Retrieve the edges in this generation Dictionary <int, List <int> > myedges = new Dictionary <int, List <int> >(); GSSGeneration cedges = edgeGenerations[i]; for (int j = 0; j != cedges.Count; j++) { GSSEdge edge = edges[cedges.Start + j]; if (!myedges.ContainsKey(edge.From)) { myedges.Add(edge.From, new List <int>()); } myedges[edge.From].Add(edge.To); if (!linked.Contains(edge.To)) { linked.Add(edge.To); } } // Retrieve the nodes in this generation and reverse their order GSSGeneration cnodes = nodeGenerations[i]; List <int> mynodes = new List <int>(); for (int j = 0; j != cnodes.Count; j++) { mynodes.Add(cnodes.Start + j); } mynodes.Reverse(); // print this generation foreach (int node in mynodes) { string mark = linked.Contains(node) ? "node" : "head"; if (myedges.ContainsKey(node)) { foreach (int to in myedges[node]) { int gen = GetGenerationOf(to); if (gen == i) { writer.WriteLine("\t{0} {1} to {2}", mark, nodeLabels[node], nodeLabels[to]); } else { writer.WriteLine("\t{0} {1} to {2} in gen {3}", mark, nodeLabels[node], nodeLabels[to], gen); } } } else { writer.WriteLine("\t{0} {1}", mark, nodeLabels[node]); } } } }
/// <summary> /// Creates a new node in the GSS /// </summary> /// <param name="state">The GLR state represented by the node</param> /// <returns>The node's identifier</returns> public int CreateNode(int state) { int node = nodeLabels.Add(state); GSSGeneration data = nodeGenerations[generation]; data.Count++; nodeGenerations[generation] = data; return(node); }
/// <summary> /// Retrieve the generation of the given node in this GSS /// </summary> /// <param name="node">A node's index</param> /// <returns>The index of the generation containing the node</returns> private int GetGenerationOf(int node) { for (int i = generation; i != -1; i--) { GSSGeneration gen = nodeGenerations[i]; if (node >= gen.Start && node < gen.Start + gen.Count) { return(i); } } // should node happen return(-1); }
/// <summary> /// Finds in the given generation a node representing the given GLR state /// </summary> /// <param name="generation">A generation</param> /// <param name="state">A GLR state</param> /// <returns>The node representing the GLR state, or -1 if it is not found</returns> public int FindNode(int generation, int state) { GSSGeneration data = nodeGenerations[generation]; for (int i = data.Start; i != data.Start + data.Count; i++) { if (nodeLabels[i] == state) { return(i); } } return(-1); }
/// <summary> /// Determines whether this instance has the required edge /// </summary> /// <param name="generation">The generation of the edge's start node</param> /// <param name="from">The edge's start node</param> /// <param name="to">The edge's target node</param> /// <returns><c>true</c> if this instance has the required edge; otherwise, <c>false</c></returns> public bool HasEdge(int generation, int from, int to) { GSSGeneration data = edgeGenerations[generation]; for (int i = data.Start; i != data.Start + data.Count; i++) { GSSEdge edge = edges[i]; if (edge.From == from && edge.To == to) { return(true); } } return(false); }
/// <summary> /// Raises an error on an unexepcted token /// </summary> /// <param name="stem">The size of the generation's stem</param> private void OnUnexpectedToken(int stem) { // build the list of expected terminals List <Symbol> expected = new List <Symbol>(); GSSGeneration genData = gss.GetGeneration(); for (int i = 0; i != genData.Count; i++) { LRExpected expectedOnHead = parserAutomaton.GetExpected(gss.GetRepresentedState(i + genData.Start), lexer.Terminals); // register the terminals for shift actions foreach (Symbol terminal in expectedOnHead.Shifts) { if (!expected.Contains(terminal)) { expected.Add(terminal); } } if (i < stem) { // the state was in the stem, also look for reductions foreach (Symbol terminal in expectedOnHead.Reductions) { if (!expected.Contains(terminal) && CheckIsExpected(i + genData.Start, terminal)) { expected.Add(terminal); } } } } // register the error UnexpectedTokenError error = new UnexpectedTokenError(lexer.tokens[nextToken.Index], new ROList <Symbol>(expected)); allErrors.Add(error); #if !NETSTANDARD1_0 if (ModeDebug) { Console.WriteLine("==== RNGLR parsing error:"); Console.Write("\t"); Console.WriteLine(error); TextContext context = lexer.Input.GetContext(error.Position); Console.Write("\t"); Console.WriteLine(context.Content); Console.Write("\t"); Console.WriteLine(context.Pointer); gss.Print(); } #endif }
/// <summary> /// Gets all paths in the GSS starting at the given node and with the given length /// </summary> /// <param name="from">The starting node</param> /// <param name="length">The length of the requested paths</param> /// <param name="count">The number of paths</param> /// <returns>A collection of paths in this GSS</returns> public GSSPath[] GetPaths(int from, int length, out int count) { if (length == 0) { // use the common 0-length GSS path to avoid new memory allocation path0.Last = from; count = 1; return(paths0); } // Initializes the first path SetupPath(0, from, length); // The number of paths in the list int total = 1; // For the remaining hops for (int i = 0; i != length; i++) { int m = 0; // Insertion index for the compaction process int next = total; // Insertion index for new paths for (int p = 0; p != total; p++) { int last = paths[p].Last; int genIndex = paths[p].Generation; // Look for new additional paths from last GSSGeneration gen = edgeGenerations[genIndex]; int firstEdgeTarget = -1; int firstEdgeLabel = -1; for (int e = gen.Start; e != gen.Start + gen.Count; e++) { GSSEdge edge = edges[e]; if (edge.From == last) { if (firstEdgeTarget == -1) { // This is the first edge firstEdgeTarget = edge.To; firstEdgeLabel = edge.Label; } else { // Not the first edge // Clone and extend the new path SetupPath(next, edge.To, length); paths[next].CopyLabelsFrom(paths[p], i); paths[next][i] = edge.Label; // Go to next insert next++; } } } // Check whether there was at least one edge if (firstEdgeTarget != -1) { // Continue the current path if (m != p) { GSSPath t = paths[m]; paths[m] = paths[p]; paths[p] = t; } paths[m].Last = firstEdgeTarget; paths[m].Generation = GetGenerationOf(firstEdgeTarget); paths[m][i] = firstEdgeLabel; // goto next m++; } } if (m != total) { // if some previous paths have been removed // => compact the list if needed for (int p = total; p != next; p++) { GSSPath t = paths[m]; paths[m] = paths[p]; paths[p] = t; m++; } // m is now the exact number of paths total = m; } else if (next != total) { // no path has been removed, but some have been added // => next is the exact number of paths total = next; } } count = total; return(paths); }