Beispiel #1
0
        /// <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));
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        /// <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));
        }
Beispiel #4
0
 /// <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));
         }
     }
 }
Beispiel #5
0
 /// <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);
     }
 }