protected override T DefaultProduction( string capturedValue, Stack <ParseTree.Node> operandStack, ProductionObjects productions) { throw new ParseErrorException(); }
protected virtual T DefaultProduction( string capturedValue, Stack <ParseTree.Node> operandStack, ProductionObjects productions) { return(CreateInstance()); }
protected virtual bool TestPreCondition( ParseTree.Node node, string capturedValue, Stack <ParseTree.Node> operandStack, ProductionObjects productions) { if (PreCondition == null) { return(true); } return(PreCondition(node)); }
IEnumerable <ActionSchedule> ScheduleActions(ProductionObjects childProductions) { // actions with order of definition var actionsOrder = Actions .Select((a, aIdx) => new { Self = a, Index = aIdx, a.SourceTokenId }); var dependentActions = actionsOrder .Where(a => !string.IsNullOrEmpty(a.SourceTokenId)); var independentActions = actionsOrder .Where(a => string.IsNullOrEmpty(a.SourceTokenId)); // child productions with order of creation var productionsOrder = childProductions .Select((p, pIdx) => new { Self = p.Value, Index = pIdx, TokenId = p.Key }); // schedule actions that depend on child production: // * actions x productions // * sorted by production creation order (inverted) // * and then by action definition order (inverted) var dependentActionSchedules = dependentActions .Join(productionsOrder, a => a.SourceTokenId, p => p.TokenId, (a, p) => new ActionSchedule { Action = a.Self, ActionIndex = a.Index, Production = p.Self, ProductionIndex = p.Index, }) .OrderByDescending(ap => ap.ProductionIndex) .ThenByDescending(ap => ap.ActionIndex); // insert independent actions in the right order var scheduled = new Stack <ActionSchedule>(); IEnumerable <ActionSchedule> toSchedule = dependentActionSchedules; foreach (var a in independentActions.OrderByDescending(a => a.Index)) { var scheduleAfter = toSchedule .TakeWhile(ap => ap.ActionIndex > a.Index); foreach (var ap in scheduleAfter) { scheduled.Push(ap); } scheduled.Push(new ActionSchedule { Action = a.Self }); toSchedule = toSchedule.Skip(scheduleAfter.Count()); } if (toSchedule.Any()) { foreach (var ap in toSchedule) { scheduled.Push(ap); } } return(scheduled); }
//////////////////////////////////////////////////////////////////////////////////////// /// /// RegExpr.Parser.GetProductionObjects() /// //////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Extract productions from a parse tree. /// </summary> /// <param name="root"> /// Root node of parse tree, obtained from parsing an input text with a RegExpr /// </param> /// <returns>Productions by token id</returns> ProductionObjects GetProductionObjects(ParseTree parseTree) { var outputProductions = new ProductionObjects(); var stack = new Stack <ParseTree.Node>(); stack.Push(parseTree.Root); while (stack.Any()) { var node = stack.Pop(); // Depth-first traversal if (node.TokenStream == null) { node.TokenStream = new Queue <ParseTree.Node>(node.ChildNodes.Values); node.OperandStack = new Stack <ParseTree.Node>(); node.OperatorStack = new Stack <ParseTree.Node>(); stack.Push(node); continue; } else if (node.TokenStream.Any()) { var nextNode = node.TokenStream.Dequeue(); stack.Push(node); stack.Push(nextNode); continue; } if (node.Parent == null) { continue; } var operatorStack = node.Parent.OperatorStack; var operandStack = node.Parent.OperandStack; var rule = node.Rule; if (rule == null) { // Default token (without rule definitions) // just use captured value as production node.Production = node.Value; operandStack.Push(node); } else if (rule.Delimiters != Delimiter.None) { // Delimiter token if (rule.Delimiters == Delimiter.Left) { // if left delim, push to operator stack operatorStack.Push(node); } else { // if right delim, unwind operator stack until left delim UnwindOperatorStack(HaltUnwind.AtLeftDelimiter, operatorStack, operandStack); // set left delim as left operand, delimited expr as right operand operandStack.ReverseTop(); // execute delimiter rule node.Production = rule.Execute(node); operandStack.Push(node); } } else if (rule.Operands != Operand.None) { // Operator token // unwind operator stack until lower priority operator or empty UnwindOperatorStack(HaltUnwind.AtLowerPriority, operatorStack, operandStack, rule.Priority); // if operator needs left operand but none is available, error out if (rule.Operands.HasFlag(Operand.Left) && !operandStack.Any()) { throw new ParseErrorException(); } if (rule.Operands.HasFlag(Operand.Right)) { // if needs right operand, push to operator stack operatorStack.Push(node); } else { // if left operand only, execute rule immediately node.Production = rule.Execute(node); operandStack.Push(node); } } else { // Captured value or embedded captures ("nullary operator") // execute rule immediately node.Production = rule.Execute(node); operandStack.Push(node); } if (node.IsLast) { // Last token // unwind operator stack until empty UnwindOperatorStack(HaltUnwind.WhenEmpty, operatorStack, operandStack); // get output from operand stack foreach (var operand in operandStack.Reverse()) { // check if it's a dangling left delimiter if (operand.Rule != null && operand.Rule.Delimiters == Delimiter.Left) { throw new ParseErrorException(); } // add production to parent context node.Parent.ChildProductions.Add(operand.TokenId, operand.Production); // add production to output list outputProductions.Add(operand.TokenId, operand.Production); } operandStack.Clear(); } } return(outputProductions); }