public override void Execute(ParsingContext context) { context.Status = ParserStatus.Error; var grammar = context.Language.Grammar; grammar.ReportParseError(context); // Do not recover if we're already at EOF, or if we're in command line mode if (context.CurrentParserInput.Term == grammar.Eof || context.Mode == ParseMode.CommandLine) { return; } //Try to recover from error context.Status = ParserStatus.Recovering; context.AddTrace(Resources.MsgTraceRecovering); // *** RECOVERING - searching for state with error shift *** var recovered = TryRecoverFromError(context); if (recovered) { context.AddTrace(Resources.MsgTraceRecoverSuccess); //add new trace entry context.Status = ParserStatus.Parsing; } else { context.AddTrace(Resources.MsgTraceRecoverFailed); context.Status = ParserStatus.Error; } }
//Completes reduce: pops child nodes from the stack and pushes result node into the stack protected void CompleteReduce(ParsingContext context) { var resultNode = context.CurrentParserInput; var childCount = Production.RValues.Count; //Pop stack context.ParserStack.Pop(childCount); //Copy comment block from first child; if comments precede child node, they precede the parent as well. if (resultNode.ChildNodes.Count > 0) resultNode.Comments = resultNode.ChildNodes[0].Comments; //Inherit precedence and associativity, to cover a standard case: BinOp->+|-|*|/; // BinOp node should inherit precedence from underlying operator symbol. //TODO: this special case will be handled differently. A ToTerm method should be expanded to allow "combined" terms like "NOT LIKE". // OLD COMMENT: A special case is SQL operator "NOT LIKE" which consists of 2 tokens. We therefore inherit "max" precedence from any children if (Production.LValue.Flags.IsSet(TermFlags.InheritPrecedence)) InheritPrecedence(resultNode); //Push new node into stack and move to new state //First read the state from top of the stack context.CurrentParserState = context.ParserStack.Top.State; if (context.TracingEnabled) context.AddTrace(Resources.MsgTracePoppedState, Production.LValue.Name); #region comments on special case //Special case: if a non-terminal is Transient (ex: BinOp), then result node is not this NonTerminal, but its its child (ex: symbol). // Shift action will invoke OnShifting on actual term being shifted (symbol); we need to invoke Shifting even on NonTerminal itself // - this would be more expected behavior in general. ImpliedPrecHint relies on this #endregion if (resultNode.Term != Production.LValue) //special case Production.LValue.OnShifting(context.SharedParsingEventArgs); // Shift to new state - execute shift over the non-terminal of the production. var shift = context.CurrentParserState.Actions[Production.LValue]; // Execute shift to new state shift.Execute(context); //Invoke Reduce event Production.LValue.OnReduced(context, Production, resultNode); }
public override void Execute(ParsingContext context) { context.Status = ParserStatus.Error; var grammar = context.Language.Grammar; grammar.ReportParseError(context); // Do not recover if we're already at EOF, or if we're in command line mode if (context.CurrentParserInput.Term == grammar.Eof || context.Mode == ParseMode.CommandLine) return; //Try to recover from error context.Status = ParserStatus.Recovering; context.AddTrace(Resources.MsgTraceRecovering); // *** RECOVERING - searching for state with error shift *** var recovered = TryRecoverFromError(context); if (recovered) { context.AddTrace(Resources.MsgTraceRecoverSuccess); //add new trace entry context.Status = ParserStatus.Parsing; } else { context.AddTrace(Resources.MsgTraceRecoverFailed); context.Status = ParserStatus.Error; } }
public override void Execute(ParsingContext context) { var traceEnabled = context.TracingEnabled; if (traceEnabled) { context.AddTrace("Conditional Parser Action."); } for (int i = 0; i < ConditionalEntries.Count; i++) { var ce = ConditionalEntries[i]; if (traceEnabled) { context.AddTrace(" Checking condition: " + ce.Description); } if (ce.Condition(context)) { if (traceEnabled) { context.AddTrace(" Condition is TRUE, executing action: " + ce.Action.ToString()); } ce.Action.Execute(context); return; } } //if no conditions matched, execute default action if (DefaultAction == null) { context.AddParserError("Fatal parser error: no conditions matched in conditional parser action, and default action is null." + " State: {0}", context.CurrentParserState.Name); context.Parser.RecoverFromError(); return; } if (traceEnabled) { context.AddTrace(" All conditions failed, executing default action: " + DefaultAction.ToString()); } DefaultAction.Execute(context); } //method
public override void Execute(ParsingContext context) { if (context.TracingEnabled) context.AddTrace(Resources.MsgTraceExecCustomAction); //States with DefaultAction do NOT read input, so we read it here if (context.CurrentParserInput == null) context.Parser.ReadInput(); // Remember old state and input; if they don't change after custom action - it is error, we may fall into an endless loop var oldState = context.CurrentParserState; var oldInput = context.CurrentParserInput; ExecuteRef(context, this); //Prevent from falling into an infinite loop if (context.CurrentParserState == oldState && context.CurrentParserInput == oldInput) { context.AddParserError(Resources.MsgErrorCustomActionDidNotAdvance); context.Parser.RecoverFromError(); } }//method
protected bool TryRecoverFromError(ParsingContext context) { var grammar = context.Language.Grammar; var parser = context.Parser; //1. We need to find a state in the stack that has a shift item based on error production (with error token), // and error terminal is current. This state would have a shift action on error token. ParserAction errorShiftAction = FindErrorShiftActionInStack(context); if (errorShiftAction == null) { return(false); //we failed to recover } context.AddTrace(Resources.MsgTraceRecoverFoundState, context.CurrentParserState); //2. Shift error token - execute shift action context.AddTrace(Resources.MsgTraceRecoverShiftError, errorShiftAction); errorShiftAction.Execute(context); //4. Now we need to go along error production until the end, shifting tokens that CAN be shifted and ignoring others. // We shift until we can reduce context.AddTrace(Resources.MsgTraceRecoverShiftTillEnd); while (true) { if (context.CurrentParserInput == null) { parser.ReadInput(); } if (context.CurrentParserInput.Term == grammar.Eof) { return(false); } //Check if we can reduce var nextAction = parser.GetNextAction(); if (nextAction == null) { parser.ReadInput(); continue; } if (nextAction is ReduceParserAction) { //We are reducing a fragment containing error - this is the end of recovery //Clear all input token queues and buffered input, reset location back to input position token queues; context.SetSourceLocation(context.CurrentParserInput.Span.Location); //Reduce error production - it creates parent non-terminal that "hides" error inside context.AddTrace(Resources.MsgTraceRecoverReducing); context.AddTrace(Resources.MsgTraceRecoverAction, nextAction); nextAction.Execute(context); //execute reduce return(true); //we recovered } // If it is not reduce, simply execute it (it is most likely shift) context.AddTrace(Resources.MsgTraceRecoverAction, nextAction); nextAction.Execute(context); //shift input token } }//method
//Completes reduce: pops child nodes from the stack and pushes result node into the stack protected void CompleteReduce(ParsingContext context) { var resultNode = context.CurrentParserInput; var childCount = Production.RValues.Count; //Pop stack context.ParserStack.Pop(childCount); //Copy comment block from first child; if comments precede child node, they precede the parent as well. if (resultNode.ChildNodes.Count > 0) { resultNode.Comments = resultNode.ChildNodes[0].Comments; } //Inherit precedence and associativity, to cover a standard case: BinOp->+|-|*|/; // BinOp node should inherit precedence from underlying operator symbol. //TODO: this special case will be handled differently. A ToTerm method should be expanded to allow "combined" terms like "NOT LIKE". // OLD COMMENT: A special case is SQL operator "NOT LIKE" which consists of 2 tokens. We therefore inherit "max" precedence from any children if (Production.LValue.Flags.IsSet(TermFlags.InheritPrecedence)) { InheritPrecedence(resultNode); } //Push new node into stack and move to new state //First read the state from top of the stack context.CurrentParserState = context.ParserStack.Top.State; if (context.TracingEnabled) { context.AddTrace(Resources.MsgTracePoppedState, Production.LValue.Name); } #region comments on special case //Special case: if a non-terminal is Transient (ex: BinOp), then result node is not this NonTerminal, but its its child (ex: symbol). // Shift action will invoke OnShifting on actual term being shifted (symbol); we need to invoke Shifting even on NonTerminal itself // - this would be more expected behavior in general. ImpliedPrecHint relies on this #endregion if (resultNode.Term != Production.LValue) //special case { Production.LValue.OnShifting(context.SharedParsingEventArgs); } // Shift to new state - execute shift over the non-terminal of the production. var shift = context.CurrentParserState.Actions[Production.LValue]; // Execute shift to new state shift.Execute(context); //Invoke Reduce event Production.LValue.OnReduced(context, Production, resultNode); }
public override void Execute(ParsingContext context) { if (context.TracingEnabled) { context.AddTrace(Resources.MsgTraceExecCustomAction); } //States with DefaultAction do NOT read input, so we read it here if (context.CurrentParserInput == null) { context.Parser.ReadInput(); } // Remember old state and input; if they don't change after custom action - it is error, we may fall into an endless loop var oldState = context.CurrentParserState; var oldInput = context.CurrentParserInput; ExecuteRef(context, this); //Prevent from falling into an infinite loop if (context.CurrentParserState == oldState && context.CurrentParserInput == oldInput) { context.AddParserError(Resources.MsgErrorCustomActionDidNotAdvance); context.Parser.RecoverFromError(); } }//method
protected bool TryRecoverFromError(ParsingContext context) { var grammar = context.Language.Grammar; var parser = context.Parser; //1. We need to find a state in the stack that has a shift item based on error production (with error token), // and error terminal is current. This state would have a shift action on error token. ParserAction errorShiftAction = FindErrorShiftActionInStack(context); if (errorShiftAction == null) return false; //we failed to recover context.AddTrace(Resources.MsgTraceRecoverFoundState, context.CurrentParserState); //2. Shift error token - execute shift action context.AddTrace(Resources.MsgTraceRecoverShiftError, errorShiftAction); errorShiftAction.Execute(context); //4. Now we need to go along error production until the end, shifting tokens that CAN be shifted and ignoring others. // We shift until we can reduce context.AddTrace(Resources.MsgTraceRecoverShiftTillEnd); while (true) { if (context.CurrentParserInput == null) parser.ReadInput(); if (context.CurrentParserInput.Term == grammar.Eof) return false; //Check if we can reduce var nextAction = parser.GetNextAction(); if (nextAction == null) { parser.ReadInput(); continue; } if (nextAction is ReduceParserAction) { //We are reducing a fragment containing error - this is the end of recovery //Clear all input token queues and buffered input, reset location back to input position token queues; context.SetSourceLocation(context.CurrentParserInput.Span.Location); //Reduce error production - it creates parent non-terminal that "hides" error inside context.AddTrace(Resources.MsgTraceRecoverReducing); context.AddTrace(Resources.MsgTraceRecoverAction, nextAction); nextAction.Execute(context); //execute reduce return true; //we recovered } // If it is not reduce, simply execute it (it is most likely shift) context.AddTrace(Resources.MsgTraceRecoverAction, nextAction); nextAction.Execute(context); //shift input token } }