Example #1
0
File: GSS.cs Project: sebgod/hime
 /// <summary>
 /// Initializes the GSS
 /// </summary>
 public GSS()
 {
     nodeLabels      = new BigList <int>();
     nodeGenerations = new BigList <GSSGeneration>();
     edges           = new BigList <GSSEdge>();
     edgeGenerations = new BigList <GSSGeneration>();
     generation      = -1;
     path0           = new GSSPath();
     paths0          = new [] { path0 };
     paths           = new GSSPath[INIT_PATHS_COUNT];
 }
Example #2
0
 /// <summary>
 /// Prepares for the forthcoming reduction operations
 /// </summary>
 /// <param name="first">The first label</param>
 /// <param name="path">The path being reduced</param>
 /// <param name="length">The reduction length</param>
 public void ReductionPrepare(int first, GSSPath path, int length)
 {
     // build the stack
     if (length > 0)
     {
         for (int i = 0; i < length - 1; i++)
         {
             stack[i] = path[length - 2 - i];
         }
         stack[length - 1] = first;
     }
     // initialize the reduction data
     cacheNext  = 0;
     handleNext = 0;
     popCount   = 0;
 }
Example #3
0
File: GSS.cs Project: sebgod/hime
 /// <summary>
 /// Setups a reusable GSS path with the given length
 /// </summary>
 /// <param name="index">The index in the buffer of reusable paths</param>
 /// <param name="last">The last GLR state in the path</param>
 /// <param name="length">The path's length</param>
 private void SetupPath(int index, int last, int length)
 {
     if (index >= paths.Length)
     {
         Array.Resize(ref paths, paths.Length + INIT_PATHS_COUNT);
     }
     if (paths[index] == null)
     {
         paths[index] = new GSSPath(length);
     }
     else
     {
         paths[index].Ensure(length);
     }
     paths[index].Last       = last;
     paths[index].Generation = GetGenerationOf(last);
 }
Example #4
0
        /// <summary>
        /// Builds the SPPF
        /// </summary>
        /// <param name="generation">The current GSS generation</param>
        /// <param name="production">The LR production</param>
        /// <param name="first">The first label of the path</param>
        /// <param name="path">The reduction path</param>
        /// <returns>The identifier of the corresponding SPPF node</returns>
        private int BuildSPPF(int generation, LRProduction production, int first, GSSPath path)
        {
            Symbol variable = symVariables[production.Head];

            sppf.ReductionPrepare(first, path, production.ReductionLength);
            for (int i = 0; i != production.BytecodeLength; i++)
            {
                LROpCode op = production[i];
                switch (op.Base)
                {
                case LROpCodeBase.SemanticAction:
                {
                    SemanticAction action = symActions[production[i + 1].DataValue];
                    i++;
                    action.Invoke(variable, sppf);
                    break;
                }

                case LROpCodeBase.AddVirtual:
                {
                    int index = production[i + 1].DataValue;
                    sppf.ReductionAddVirtual(index, op.TreeAction);
                    i++;
                    break;
                }

                case LROpCodeBase.AddNullVariable:
                {
                    int index = production[i + 1].DataValue;
                    sppf.ReductionAddNullable(nullables[index], op.TreeAction);
                    i++;
                    break;
                }

                default:
                    sppf.ReductionPop(op.TreeAction);
                    break;
                }
            }
            return(sppf.Reduce(generation, production.Head, production.HeadAction));
        }
Example #5
0
 /// <summary>
 /// Copy the content of another path to this one
 /// </summary>
 /// <param name="path">The path to copy</param>
 /// <param name="length">The path's length</param>
 public void CopyLabelsFrom(GSSPath path, int length)
 {
     Array.Copy(path.labels, labels, length);
 }
Example #6
0
File: GSS.cs Project: sebgod/hime
        /// <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);
        }
Example #7
0
        /// <summary>
        /// Executes a reduction operation for a given path
        /// </summary>
        /// <param name="generation">The current GSS generation</param>
        /// <param name="reduction">The reduction operation</param>
        /// <param name="path">The GSS path to use for the reduction</param>
        private void ExecuteReduction(int generation, Reduction reduction, GSSPath path)
        {
            // Get the rule's head
            Symbol head = symVariables[reduction.prod.Head];
            // Resolve the sub-root
            int label = sppf.GetLabelFor(path.Generation, new TableElemRef(TableType.Variable, reduction.prod.Head));

            if (label == SPPF.EPSILON)
            {
                // not in history, build the SPPF here
                label = BuildSPPF(generation, reduction.prod, reduction.first, path);
            }

            // Get the target state by transition on the rule's head
            int to = GetNextByVar(gss.GetRepresentedState(path.Last), head.ID);
            // Find a node for the target state in the GSS
            int w = gss.FindNode(generation, to);

            if (w != -1)
            {
                // A node for the target state is already in the GSS
                if (!gss.HasEdge(generation, w, path.Last))
                {
                    // But the new edge does not exist
                    gss.CreateEdge(w, path.Last, label);
                    // Look for the new reductions at this state
                    if (reduction.prod.ReductionLength != 0)
                    {
                        int count = parserAutomaton.GetActionsCount(to, nextToken.TerminalID);
                        for (int i = 0; i != count; i++)
                        {
                            LRAction action = parserAutomaton.GetAction(to, nextToken.TerminalID, i);
                            if (action.Code == LRActionCode.Reduce)
                            {
                                LRProduction prod = parserAutomaton.GetProduction(action.Data);
                                // length 0 reduction are not considered here because they already exist at this point
                                if (prod.ReductionLength != 0)
                                {
                                    reductions.Enqueue(new Reduction(path.Last, prod, label));
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                // Create the new corresponding node in the GSS
                w = gss.CreateNode(to);
                gss.CreateEdge(w, path.Last, label);
                // Look for all the reductions and shifts at this state
                int count = parserAutomaton.GetActionsCount(to, nextToken.TerminalID);
                for (int i = 0; i != count; i++)
                {
                    LRAction action = parserAutomaton.GetAction(to, nextToken.TerminalID, i);
                    if (action.Code == LRActionCode.Shift)
                    {
                        shifts.Enqueue(new Shift(w, action.Data));
                    }
                    else if (action.Code == LRActionCode.Reduce)
                    {
                        LRProduction prod = parserAutomaton.GetProduction(action.Data);
                        if (prod.ReductionLength == 0)
                        {
                            reductions.Enqueue(new Reduction(w, prod, SPPF.EPSILON));
                        }
                        else if (reduction.prod.ReductionLength != 0)
                        {
                            reductions.Enqueue(new Reduction(path.Last, prod, label));
                        }
                    }
                }
            }
        }
Example #8
0
        /// <summary>
        /// Checks whether the specified terminal is indeed expected for a reduction
        /// </summary>
        /// <param name="gssNode">The GSS node from which to reduce</param>
        /// <param name="terminal">The terminal to check</param>
        /// <returns><code>true</code> if the terminal is really expected</returns>
        /// <remarks>
        /// This check is required because in the case of a base LALR graph,
        /// some terminals expected for reduction in the automaton are coming from other paths.
        /// </remarks>
        private bool CheckIsExpected(int gssNode, Symbol terminal)
        {
            // queue of GLR states to inspect:
            List <int>   queueGSSHead = new List <int>();           // the related GSS head
            List <int[]> queueVStack  = new List <int[]>();         // the virtual stack

            // first reduction
            {
                int count = parserAutomaton.GetActionsCount(gss.GetRepresentedState(gssNode), terminal.ID);
                for (int j = 0; j != count; j++)
                {
                    LRAction action = parserAutomaton.GetAction(gss.GetRepresentedState(gssNode), terminal.ID, j);
                    if (action.Code == LRActionCode.Reduce)
                    {
                        // execute the reduction
                        LRProduction production = parserAutomaton.GetProduction(action.Data);
                        int          nbPaths;
                        GSSPath[]    paths = gss.GetPaths(gssNode, production.ReductionLength, out nbPaths);
                        for (int k = 0; k != nbPaths; k++)
                        {
                            GSSPath path = paths[k];
                            // get the target GLR state
                            int next = GetNextByVar(gss.GetRepresentedState(path.Last), symVariables[production.Head].ID);
                            // enqueue the info, top GSS stack node and target GLR state
                            queueGSSHead.Add(path.Last);
                            queueVStack.Add(new[] { next });
                        }
                    }
                }
            }

            // now, close the queue
            for (int i = 0; i != queueGSSHead.Count; i++)
            {
                int head  = queueVStack[i][queueVStack[i].Length - 1];
                int count = parserAutomaton.GetActionsCount(head, terminal.ID);
                if (count == 0)
                {
                    continue;
                }
                for (int j = 0; j != count; j++)
                {
                    LRAction action = parserAutomaton.GetAction(head, terminal.ID, j);
                    if (action.Code == LRActionCode.Shift)
                    {
                        // yep, the terminal was expected
                        return(true);
                    }
                    if (action.Code == LRActionCode.Reduce)
                    {
                        // execute the reduction
                        LRProduction production = parserAutomaton.GetProduction(action.Data);
                        if (production.ReductionLength == 0)
                        {
                            // 0-length reduction => start from the current head
                            int[] virtualStack = new int[queueVStack[i].Length + 1];
                            Array.Copy(queueVStack[i], virtualStack, queueVStack[i].Length);
                            virtualStack[virtualStack.Length - 1] = GetNextByVar(head, symVariables[production.Head].ID);
                            // enqueue
                            queueGSSHead.Add(queueGSSHead[i]);
                            queueVStack.Add(virtualStack);
                        }
                        else if (production.ReductionLength < queueVStack[i].Length)
                        {
                            // we are still the virtual stack
                            int[] virtualStack = new int[queueVStack[i].Length - production.ReductionLength + 1];
                            Array.Copy(queueVStack[i], virtualStack, virtualStack.Length - 1);
                            virtualStack[virtualStack.Length - 1] = GetNextByVar(virtualStack[virtualStack.Length - 2], symVariables[production.Head].ID);
                            // enqueue
                            queueGSSHead.Add(queueGSSHead[i]);
                            queueVStack.Add(virtualStack);
                        }
                        else
                        {
                            // we reach the GSS
                            int       nbPaths;
                            GSSPath[] paths = gss.GetPaths(queueGSSHead[i], production.ReductionLength - queueVStack[i].Length, out nbPaths);
                            for (int k = 0; k != nbPaths; k++)
                            {
                                GSSPath path = paths[k];
                                // get the target GLR state
                                int next = GetNextByVar(gss.GetRepresentedState(path.Last), symVariables[production.Head].ID);
                                // enqueue the info, top GSS stack node and target GLR state
                                queueGSSHead.Add(path.Last);
                                queueVStack.Add(new[] { next });
                            }
                        }
                    }
                }
            }

            // nope, that was a pathological case in a LALR graph
            return(false);
        }
Example #9
0
        /// <summary>
        /// Gets the priority of the specified context required by the specified terminal
        /// The priority is a positive integer. The lesser the value the higher the priority.
        /// A value of -1 represents the unavailability of the required context.
        /// </summary>
        /// <param name="context">A context</param>
        /// <param name="onTerminalID">The identifier of the terminal requiring the context</param>
        /// <returns>The context priority, or -1 if the context is unavailable</returns>
        public int GetContextPriority(int context, int onTerminalID)
        {
            // the default context is always active
            if (context == Automaton.DEFAULT_CONTEXT)
            {
                return(int.MaxValue);
            }
            if (lexer.tokens.Size == 0)
            {
                // this is the first token, does it open the context?
                return(parserAutomaton.GetContexts(0).Opens(onTerminalID, context) ? 0 : -1);
            }
            // try to only look at stack heads that expect the terminal
            List <int>          queue       = new List <int>();
            List <LRProduction> productions = new List <LRProduction>();
            List <int>          distances   = new List <int>();
            bool foundOnPreviousShift       = false;

            foreach (Shift shift in shifts)
            {
                int count = parserAutomaton.GetActionsCount(shift.to, onTerminalID);
                if (count == 0)
                {
                    continue;
                }
                for (int i = 0; i != count; i++)
                {
                    LRAction action = parserAutomaton.GetAction(shift.to, onTerminalID, i);
                    if (action.Code == LRActionCode.Shift)
                    {
                        // does the context opens with the terminal?
                        if (parserAutomaton.GetContexts(shift.to).Opens(onTerminalID, context))
                        {
                            return(0);
                        }
                        // looking at the immediate history, does the context opens from the shift just before?
                        if (parserAutomaton.GetContexts(gss.GetRepresentedState(shift.from)).Opens(nextToken.TerminalID, context))
                        {
                            foundOnPreviousShift = true;
                            break;
                        }
                        // no, enqueue
                        if (!queue.Contains(shift.from))
                        {
                            queue.Add(shift.from);
                            productions.Add(null);
                            distances.Add(2);
                        }
                    }
                    else
                    {
                        // this is reduction
                        LRProduction production = parserAutomaton.GetProduction(action.Data);
                        // looking at the immediate history, does the context opens from the shift just before?
                        if (parserAutomaton.GetContexts(gss.GetRepresentedState(shift.from)).Opens(nextToken.TerminalID, context))
                        {
                            if (production.ReductionLength < 1)
                            {
                                // the reduction does not close the context
                                foundOnPreviousShift = true;
                                break;
                            }
                        }
                        // no, enqueue
                        if (!queue.Contains(shift.from))
                        {
                            queue.Add(shift.from);
                            productions.Add(production);
                            distances.Add(2);
                        }
                    }
                }
            }
            if (foundOnPreviousShift)
            {
                // found the context opening on the previous shift (and was not immediately closed by a reduction)
                return(1);
            }
            if (queue.Count == 0)
            {
                // the track is empty, the terminal is unexpected
                return(-1);
            }
            // explore the current GSS to find the specified context
            for (int i = 0; i != queue.Count; i++)
            {
                int       count;
                GSSPath[] paths = gss.GetPaths(queue[i], 1, out count);
                for (int p = 0; p != count; p++)
                {
                    int          from       = paths[p].Last;
                    int          symbolID   = sppf.GetSymbolOn(paths[p][0]).ID;
                    int          distance   = distances[i];
                    LRProduction production = productions[i];
                    // was the context opened on this transition?
                    if (parserAutomaton.GetContexts(gss.GetRepresentedState(from)).Opens(symbolID, context))
                    {
                        if (production == null || production.ReductionLength < distance)
                        {
                            return(distance);
                        }
                    }
                    // no, enqueue
                    if (!queue.Contains(from))
                    {
                        queue.Add(from);
                        productions.Add(production);
                        distances.Add(distance + 1);
                    }
                }
            }
            // at this point, the requested context is not yet open
            // can it be open by a token with the specified terminal ID?
            // queue of GLR states to inspect:
            List <int>   queueGSSHead = new List <int>();           // the related GSS head
            List <int[]> queueVStack  = new List <int[]>();         // the virtual stack

            // first reduction
            foreach (Shift shift in shifts)
            {
                int count = parserAutomaton.GetActionsCount(shift.to, onTerminalID);
                if (count > 0)
                {
                    // enqueue the info, top GSS stack node and target GLR state
                    queueGSSHead.Add(shift.from);
                    queueVStack.Add(new[] { shift.to });
                }
            }
            // now, close the queue
            for (int i = 0; i != queueGSSHead.Count; i++)
            {
                int head  = queueVStack[i][queueVStack[i].Length - 1];
                int count = parserAutomaton.GetActionsCount(head, onTerminalID);
                if (count == 0)
                {
                    continue;
                }
                for (int j = 0; j != count; j++)
                {
                    LRAction action = parserAutomaton.GetAction(head, onTerminalID, j);
                    if (action.Code != LRActionCode.Reduce)
                    {
                        continue;
                    }
                    // execute the reduction
                    LRProduction production = parserAutomaton.GetProduction(action.Data);
                    if (production.ReductionLength == 0)
                    {
                        // 0-length reduction => start from the current head
                        int[] virtualStack = new int[queueVStack[i].Length + 1];
                        Array.Copy(queueVStack[i], virtualStack, queueVStack[i].Length);
                        int next = GetNextByVar(head, symVariables[production.Head].ID);
                        virtualStack[virtualStack.Length - 1] = next;
                        // enqueue
                        queueGSSHead.Add(queueGSSHead[i]);
                        queueVStack.Add(virtualStack);
                    }
                    else if (production.ReductionLength < queueVStack[i].Length)
                    {
                        // we are still the virtual stack
                        int[] virtualStack = new int[queueVStack[i].Length - production.ReductionLength + 1];
                        Array.Copy(queueVStack[i], virtualStack, virtualStack.Length - 1);
                        int next = GetNextByVar(virtualStack[virtualStack.Length - 2], symVariables[production.Head].ID);
                        virtualStack[virtualStack.Length - 1] = next;
                        // enqueue
                        queueGSSHead.Add(queueGSSHead[i]);
                        queueVStack.Add(virtualStack);
                    }
                    else
                    {
                        // we reach the GSS
                        int       nbPaths;
                        GSSPath[] paths = gss.GetPaths(queueGSSHead[i], production.ReductionLength - queueVStack[i].Length, out nbPaths);
                        for (int k = 0; k != nbPaths; k++)
                        {
                            GSSPath path = paths[k];
                            // get the target GLR state
                            int next = GetNextByVar(gss.GetRepresentedState(path.Last), symVariables[production.Head].ID);
                            // enqueue the info, top GSS stack node and target GLR state
                            queueGSSHead.Add(path.Last);
                            queueVStack.Add(new[] { next });
                        }
                    }
                }
            }
            foreach (int[] vstack in queueVStack)
            {
                int state = vstack[vstack.Length - 1];
                int count = parserAutomaton.GetActionsCount(state, onTerminalID);
                for (int i = 0; i != count; i++)
                {
                    LRAction action = parserAutomaton.GetAction(state, onTerminalID, i);
                    if (action.Code == LRActionCode.Shift && parserAutomaton.GetContexts(state).Opens(onTerminalID, context))
                    {
                        // the context opens here
                        return(0);
                    }
                }
            }
            // the context is still unavailable
            return(-1);
        }