/// <summary> /// Parses the input and returns the produced AST /// </summary> /// <returns>AST produced by the parser representing the input, or null if unrecoverable errors were encountered</returns> public override ParseResult Parse() { reductions = new Queue <Reduction>(); shifts = new Queue <Shift>(); int Ui = gss.CreateGeneration(); int v0 = gss.CreateNode(0); nextToken = lexer.GetNextToken(this); // bootstrap the shifts and reductions queues int count = parserAutomaton.GetActionsCount(0, nextToken.TerminalID); for (int i = 0; i != count; i++) { LRAction action = parserAutomaton.GetAction(0, nextToken.TerminalID, i); if (action.Code == LRActionCode.Shift) { shifts.Enqueue(new Shift(v0, action.Data)); } else if (action.Code == LRActionCode.Reduce) { reductions.Enqueue(new Reduction(v0, parserAutomaton.GetProduction(action.Data), SPPF.EPSILON)); } } while (nextToken.TerminalID != Symbol.SID_EPSILON) // Wait for ε token { // the stem length (initial number of nodes in the generation before reductions) int stem = gss.GetGeneration(Ui).Count; // apply all reduction actions Reducer(Ui); // no scheduled shift actions? if (shifts.Count == 0) { // the next token was not expected OnUnexpectedToken(stem); return(new ParseResult(new ROList <ParseError>(allErrors), lexer.Input)); } // look for the next next-token Lexer.TokenKernel oldtoken = nextToken; nextToken = lexer.GetNextToken(this); // apply the scheduled shift actions Ui = Shifter(oldtoken); } GSSGeneration genData = gss.GetGeneration(Ui); for (int i = genData.Start; i != genData.Start + genData.Count; i++) { int state = gss.GetRepresentedState(i); if (parserAutomaton.IsAcceptingState(state)) { // Has reduction _Axiom_ -> axiom $ . on ε GSSPath[] paths = gss.GetPaths(i, 2, out count); return(new ParseResult(new ROList <ParseError>(allErrors), lexer.Input, sppf.GetTree(paths[0][1]))); } } // At end of input but was still waiting for tokens return(new ParseResult(new ROList <ParseError>(allErrors), lexer.Input)); }
/// <summary> /// Executes the shift operations for the given token /// </summary> /// <param name="oldtoken">A token</param> /// <returns>The next generation</returns> private int Shifter(Lexer.TokenKernel oldtoken) { // Create next generation int gen = gss.CreateGeneration(); // Create the GSS label to be used for the transitions TableElemRef sym = new TableElemRef(TableType.Token, oldtoken.Index); int label = sppf.GetSingleNode(sym); // Execute all shifts in the queue at this point int count = shifts.Count; for (int i = 0; i != count; i++) { ExecuteShift(gen, label, shifts.Dequeue()); } return(gen); }
/// <summary> /// Raises an error on an unexpected token /// </summary> /// <param name="kernel">The unexpected token's kernel</param> /// <returns>The next token kernel in the case the error is recovered</returns> private Lexer.TokenKernel OnUnexpectedToken(Lexer.TokenKernel kernel) { LRExpected expectedOnHead = automaton.GetExpected(stack[head], lexer.Terminals); // the terminals for shifts are always expected List <Symbol> expected = new List <Symbol>(expectedOnHead.Shifts); // check the terminals for reductions foreach (Symbol terminal in expectedOnHead.Reductions) { if (CheckIsExpected(terminal)) { expected.Add(terminal); } } // register the error allErrors.Add(new UnexpectedTokenError(lexer.tokens[kernel.Index], new ROList <Symbol>(expected))); // TODO: try to recover, or not return(new Lexer.TokenKernel(Symbol.SID_NOTHING, -1)); }
/// <summary> /// Parses the input and returns the result /// </summary> /// <returns>A ParseResult object containing the data about the result</returns> public override ParseResult Parse() { Lexer.TokenKernel nextKernel = lexer.GetNextToken(this); while (true) { LRActionCode action = ParseOnToken(nextKernel); if (action == LRActionCode.Shift) { nextKernel = lexer.GetNextToken(this); continue; } if (action == LRActionCode.Accept) { return(new ParseResult(new ROList <ParseError>(allErrors), lexer.Input, builder.GetTree())); } nextKernel = OnUnexpectedToken(nextKernel); if (nextKernel.TerminalID == Symbol.SID_NOTHING || allErrors.Count >= MAX_ERROR_COUNT) { return(new ParseResult(new ROList <ParseError>(allErrors), lexer.Input)); } } }
/// <summary> /// Parses on the specified token kernel /// </summary> /// <param name="kernel">The token kernel to parse on</param> /// <returns>The LR action that was used</returns> private LRActionCode ParseOnToken(Lexer.TokenKernel kernel) { while (true) { LRAction action = automaton.GetAction(stack[head], kernel.TerminalID); if (action.Code == LRActionCode.Shift) { head++; if (head == stack.Length) { Array.Resize(ref stack, stack.Length + INIT_STACK_SIZE); Array.Resize(ref stackIDs, stackIDs.Length + INIT_STACK_SIZE); } stack[head] = action.Data; stackIDs[head] = kernel.TerminalID; builder.StackPushToken(kernel.Index); return(action.Code); } if (action.Code == LRActionCode.Reduce) { LRProduction production = automaton.GetProduction(action.Data); head -= production.ReductionLength; Reduce(production); action = automaton.GetAction(stack[head], symVariables[production.Head].ID); head++; if (head == stack.Length) { Array.Resize(ref stack, stack.Length + INIT_STACK_SIZE); Array.Resize(ref stackIDs, stackIDs.Length + INIT_STACK_SIZE); } stack[head] = action.Data; stackIDs[head] = symVariables[production.Head].ID; continue; } return(action.Code); } }