/// <summary> /// During a reduction, inserts a virtual symbol /// </summary> /// <param name="index">The virtual symbol's index</param> /// <param name="action">The tree action applied onto the symbol</param> public void ReductionAddVirtual(int index, TreeAction action) { if (action == TreeAction.Drop) { return; // why would you do this? } int nodeId = sppf.NewNode(new TableElemRef(TableType.Virtual, index)); if (cacheNext + 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(nodeId, 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 handleNext++; cacheNext++; }
/// <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)); }
/// <summary> /// Gets the symbol at the i-th index /// </summary> /// <param name="index">Index of the symbol</param> /// <returns>The symbol at the given index</returns> public SemanticElement this[int index] { get { SPPFNodeRef reference = cacheChildren[handleIndices[index]]; SPPFNode sppfNode = sppf.GetNode(reference.NodeId); TableElemRef label = (sppfNode as SPPFNodeNormal).GetVersion(reference.Version).Label; return(result.GetSemanticElementForLabel(label)); } }
/// <summary> /// Adds a new version to this node /// </summary> /// <param name="label">The label for this version of the node</param> /// <param name="children">A buffer of children for this version of the node</param> /// <param name="childrenCount">The number of children</param> /// <returns>The reference to this new version</returns> public SPPFNodeRef NewVersion(TableElemRef label, SPPFNodeRef[] children, int childrenCount) { if (versionsCount == versions.Length) { Array.Resize(ref versions, versions.Length + VERSION_COUNT); } versions[versionsCount] = new SPPFNodeVersion(label, children, childrenCount); SPPFNodeRef result = new SPPFNodeRef(identifier, versionsCount); versionsCount++; return(result); }
/// <summary> /// Builds the final AST for the specified SPPF node reference /// </summary> /// <param name="reference">A reference to an SPPF node in a specific version</param> /// <returns>The AST node for the SPPF reference</returns> public AST.Node BuildFinalAST(SPPFNodeRef reference) { SPPFNode sppfNode = sppf.GetNode(reference.NodeId); SPPFNodeVersion version = (sppfNode as SPPFNodeNormal).GetVersion(reference.Version); if (version.ChildrenCount == 0) { return(new AST.Node(version.Label)); } AST.Node[] buffer = new AST.Node[version.ChildrenCount]; for (int i = 0; i != version.ChildrenCount; i++) { buffer[i] = BuildFinalAST(version.Children[i]); } int first = result.Store(buffer, 0, version.ChildrenCount); return(new AST.Node(version.Label, version.ChildrenCount, first)); }