/// <summary> /// Adds the specified SPPF node to the cache /// </summary> /// <param name="node">The node to add to the cache</param> /// <param name="action">The tree action to apply onto the node</param> private void AddToCache(SPPFNodeNormal node, TreeAction action) { SPPFNodeVersion version = node.DefaultVersion; while (cacheNext + version.ChildrenCount + 1 >= cacheChildren.Length) { // the current cache is not big enough, build a bigger one Array.Resize(ref cacheChildren, cacheChildren.Length + INIT_HANDLE_SIZE); } // add the node in the cache cacheChildren[cacheNext] = new SPPFNodeRef(node.Identifier, 0); // setup the handle to point to the root if (handleNext == handleIndices.Length) { Array.Resize(ref handleIndices, handleIndices.Length + INIT_HANDLE_SIZE); Array.Resize(ref handleActions, handleActions.Length + INIT_HANDLE_SIZE); } handleIndices[handleNext] = cacheNext; handleActions[handleNext] = action; // copy the children if (version.ChildrenCount > 0) { Array.Copy(version.Children, 0, cacheChildren, cacheNext + 1, version.ChildrenCount); } handleNext++; cacheNext += version.ChildrenCount + 1; }
/// <summary> /// Executes the reduction as a normal reduction /// </summary> /// <param name="varIndex">The reduced variable index</param> /// <param name="headAction">The tree action applied in the rule's head</param> /// <returns>The identifier of the produced SPPF node</returns> private int ReduceNormal(int varIndex, TreeAction headAction) { TableElemRef promotedSymbol = new TableElemRef(); SPPFNodeRef promotedReference = new SPPFNodeRef(SPPF.EPSILON, 0); int insertion = 0; for (int i = 0; i != handleNext; i++) { switch (handleActions[i]) { case TreeAction.Promote: if (promotedReference.NodeId != SPPF.EPSILON) { // not the first promotion // create a new version for the promoted node SPPFNodeNormal oldPromotedNode = sppf.GetNode(promotedReference.NodeId) as SPPFNodeNormal; SPPFNodeRef oldPromotedRef = oldPromotedNode.NewVersion(promotedSymbol, cacheChildren, insertion); // register the previously promoted reference into the cache cacheChildren[0] = oldPromotedRef; insertion = 1; } // save the new promoted node promotedReference = cacheChildren[handleIndices[i]]; SPPFNodeNormal promotedNode = sppf.GetNode(promotedReference.NodeId) as SPPFNodeNormal; SPPFNodeVersion promotedVersion = promotedNode.GetVersion(promotedReference.Version); promotedSymbol = promotedVersion.Label; // repack the children on the left if any Array.Copy(cacheChildren, handleIndices[i] + 1, cacheChildren, insertion, promotedVersion.ChildrenCount); insertion += promotedVersion.ChildrenCount; break; default: // Repack the sub-root on the left if (insertion != handleIndices[i]) { cacheChildren[insertion] = cacheChildren[handleIndices[i]]; } insertion++; break; } } TableElemRef originalLabel = new TableElemRef(TableType.Variable, varIndex); TableElemRef currentLabel = originalLabel; if (promotedReference.NodeId != SPPF.EPSILON) { // a promotion occurred currentLabel = promotedSymbol; } else if (headAction == TreeAction.ReplaceByEpsilon) { // this variable must be replaced in the final AST currentLabel = new TableElemRef(TableType.None, 0); } return(sppf.NewNode(originalLabel, currentLabel, cacheChildren, insertion)); }