Пример #1
0
 protected void OnActionSelected(Token input, ActionRecord action)
 {
     Data.Grammar.OnActionSelected(this, _currentToken, action);
     if (ActionSelected != null)
     {
         ParserActionEventArgs args = new ParserActionEventArgs(this.CurrentState, input, action);
         ActionSelected(this, args);
     }
 }
        }//methods

        private bool CheckConflictResolutionByPrecedence(ActionRecord action)
        {
            SymbolTerminal opTerm = SymbolTerminal.GetSymbol(action.Key);

            if (opTerm != null && opTerm.IsSet(TermOptions.IsOperator))
            {
                action.ActionType       = ParserActionType.Operator;
                action.ConflictResolved = true;
                return(true);
            }
            return(false);
        }
Пример #3
0
        //TODO: need to rewrite, looks ugly
        private bool Recover()
        {
            //for recovery the current token must be error token, we rely on it
            if (!_currentToken.IsError())
            {
                _currentToken = _context.CreateErrorToken(_currentToken.Location, _currentToken.Text);
            }
            //Check the current state and states in stack for error shift action - this would be recovery state.
            ActionRecord action = GetCurrentAction();

            if (action == null || action.ActionType == ParserActionType.Reduce)
            {
                while (Stack.Count > 0)
                {
                    _currentState = Stack.Top.State;
                    Stack.Pop(1);
                    action = GetCurrentAction();
                    if (action != null && action.ActionType != ParserActionType.Reduce)
                    {
                        break; //we found shift action for error token
                    }
                }//while
            }//if
            if (action == null || action.ActionType == ParserActionType.Reduce)
            {
                return(false); //could not find shift action, cannot recover
            }
            //We found recovery state, and action contains ActionRecord for "error shift". Lets shift it.
            ExecuteShiftAction(action);//push the error token
            // Now shift all tokens from input that can be shifted.
            // These are the ones that are found in error production after the error. We ignore all other tokens
            // We stop when we find a state with reduce-only action.
            while (_currentToken.Terminal != Grammar.Eof)
            {
                //with current token, see if we can shift it.
                action = GetCurrentAction();
                if (action == null)
                {
                    NextToken(); //skip this token and continue reading input
                    continue;
                }
                if (action.ActionType == ParserActionType.Reduce || action.ActionType == ParserActionType.Operator)
                {
                    //we can reduce - let's reduce and return success - we recovered.
                    ExecuteReduceAction(action);
                    return(true);
                }
                //it is shift action, let's shift
                ExecuteShiftAction(action);
            }//while
            return(false); //
        }
        }         //method

        //Checks Reduce productions of an action for a ReduceThis hint. If found, the production is moved to the beginning of the list.
        private bool CheckReduceHint(ActionRecord action)
        {
            foreach (Production prod in action.ReduceProductions)
            {
                GrammarHint reduceHint = GetHint(prod, prod.RValues.Count, HintType.ReduceThis);
                if (reduceHint != null)
                {
                    action.ReduceProductions.Remove(prod);
                    action.ReduceProductions.Insert(0, prod);
                    action.ActionType       = ParserActionType.Reduce;
                    action.ConflictResolved = true;
                    return(true);
                } //if
            }     //foreach prod
            return(false);
        }         //method
 //Checks  shift items for PreferShift grammar hint. Hints are associated with a particular position
 // inside production, which is in fact an LR0 item. The LR0 item is available thru shiftItem.Core property.
 // If PreferShift hint found, moves the hint-owning shiftItem to the beginning of the list and returns true.
 private bool CheckShiftHint(ActionRecord action)
 {
     foreach (LRItem shiftItem in action.ShiftItems)
     {
         GrammarHint shiftHint = GetHint(shiftItem.Core.Production, shiftItem.Core.Position, HintType.PreferShift);
         if (shiftHint != null)
         {
             action.ActionType = ParserActionType.Shift;
             action.ShiftItems.Remove(shiftItem);
             action.ShiftItems.Insert(0, shiftItem);
             action.ConflictResolved = true;
             return(true);
         } //if
     }     //foreach shiftItem
     return(false);
 }         //method
        private void CreateParserStates()
        {
            Data.States.Clear();
            _stateHash = new ParserStateTable();
            CreateInitialAndFinalStates();

            string augmRootKey = Data.AugmentedRoot.Key;

            // Iterate through states (while new ones are created) and create shift transitions and new states
            for (int index = 0; index < Data.States.Count; index++)
            {
                ParserState state = Data.States[index];
                AddClosureItems(state);
                //Get keys of all possible shifts
                ShiftTable shiftTable = GetStateShifts(state);
                //Each key in shifts dict is an input element
                // Value is LR0ItemList of shifted LR0Items for this input element.
                foreach (string input in shiftTable.Keys)
                {
                    LR0ItemList  shiftedCoreItems = shiftTable[input];
                    ParserState  newState         = FindOrCreateState(shiftedCoreItems);
                    ActionRecord newAction        = new ActionRecord(input, ParserActionType.Shift, newState, null);
                    state.Actions[input] = newAction;
                    //link original LRItems in original state to derived LRItems in newState
                    foreach (LR0Item coreItem in shiftedCoreItems)
                    {
                        LRItem fromItem = FindItem(state, coreItem.Production, coreItem.Position - 1);
                        LRItem toItem   = FindItem(newState, coreItem.Production, coreItem.Position);
                        if (!fromItem.PropagateTargets.Contains(toItem))
                        {
                            fromItem.PropagateTargets.Add(toItem);
                        }
                        //copy hints from core items into the newAction
                        newAction.ShiftItems.Add(fromItem);
                    } //foreach coreItem
                }     //foreach input
            }         //for index
            Data.FinalState = Data.InitialState.Actions[augmRootKey].NewState;
        }             //method
Пример #7
0
        private ActionRecord GetCurrentAction()
        {
            ActionRecord action = null;

            if (_currentToken.MatchByValue)
            {
                string key = CurrentToken.Text;
                if (!_caseSensitive)
                {
                    key = key.ToLower();
                }
                if (_currentState.Actions.TryGetValue(key, out action))
                {
                    return(action);
                }
            }
            if (_currentToken.MatchByType && _currentState.Actions.TryGetValue(_currentToken.Terminal.Key, out action))
            {
                return(action);
            }
            return(null); //action not found
        }
Пример #8
0
 public ParserActionEventArgs(ParserState state, Token input, ActionRecord action)
 {
     State  = state;
     Input  = input;
     Action = action;
 }
Пример #9
0
        }//method

        private AstNode CreateNode(ActionRecord reduceAction, SourceSpan sourceSpan, AstNodeList childNodes)
        {
            NonTerminal nt = reduceAction.NonTerminal;
            AstNode     result;
            NodeArgs    nodeArgs = new NodeArgs(_context, nt, sourceSpan, childNodes);

            if (nt.NodeCreator != null)
            {
                result = nt.NodeCreator(nodeArgs);
                if (result != null)
                {
                    return(result);
                }
            }

            Type defaultNodeType = _context.Compiler.Grammar.DefaultNodeType;
            Type ntNodeType      = nt.NodeType ?? defaultNodeType ?? typeof(AstNode);

            // Check if NonTerminal is a list
            // List nodes are produced by .Plus() or .Star() methods of BnfElement
            // In this case, we have a left-recursive list formation production:
            //     ntList -> ntList + delim? + ntElem
            //  We check if we have already created the list node for ntList (in the first child);
            //  if yes, we use this child as a result directly, without creating new list node.
            //  The other incoming child - the last one - is a new list member;
            // we simply add it to child list of the result ntList node. Optional "delim" node is simply thrown away.
            bool isList = nt.IsSet(TermOptions.IsList);

            if (isList && childNodes.Count > 1 && childNodes[0].Term == nt)
            {
                result = childNodes[0];
                AstNode newChild = childNodes[childNodes.Count - 1];
                newChild.Parent = result;
                result.ChildNodes.Add(newChild);
                return(result);
            }
            //Check for StarList produced by MakeStarRule; in this case the production is:  ntList -> Empty | Elem+
            // where Elem+ is non-empty list of elements. The child list we are actually interested in is one-level lower
            if (nt.IsSet(TermOptions.IsStarList) && childNodes.Count == 1)
            {
                childNodes = childNodes[0].ChildNodes;
            }
            // Check for "node-bubbling" case. For identity productions like
            //   A -> B
            // the child node B is usually a subclass of node A,
            // so child node B can be used directly in place of the A. So we simply return child node as a result.
            // TODO: probably need a grammar option to enable/disable this behavior explicitly
            bool canBubble = (Data.Grammar.FlagIsSet(LanguageFlags.BubbleNodes)) &&
                             !isList && !nt.IsSet(TermOptions.IsPunctuation) && childNodes.Count == 1 && (childNodes[0].Term is NonTerminal);

            if (canBubble)
            {
                NonTerminal childNT       = childNodes[0].Term as NonTerminal;
                Type        childNodeType = childNT.NodeType ?? defaultNodeType ?? typeof(AstNode);
                if (childNodeType == ntNodeType || childNodeType.IsSubclassOf(ntNodeType))
                {
                    return(childNodes[0]);
                }
            }
            // Try using Grammar's CreateNode method
            result = Data.Grammar.CreateNode(_context, reduceAction, sourceSpan, childNodes);
            if (result != null)
            {
                return(result);
            }

            //Finally create node directly. For perf reasons we try using "new" for AstNode type (faster), and
            // activator for all custom types (slower)
            if (ntNodeType == typeof(AstNode))
            {
                return(new AstNode(nodeArgs));
            }

            // if (ntNodeType.GetConstructor(new Type[] {typeof(AstNodeList)}) != null)
            // return (AstNode)Activator.CreateInstance(ntNodeType, childNodes);
            if (ntNodeType.GetConstructor(new Type[] { typeof(NodeArgs) }) != null)
            {
                return((AstNode)Activator.CreateInstance(ntNodeType, nodeArgs));
            }
            //The following should never happen - we check that constructor exists when we validate grammar.
            string msg = string.Format(
                @"AST Node class {0} does not have a constructor for automatic node creation. 
Provide a constructor with a single NodeArgs parameter, or use NodeCreator delegate property in NonTerminal.", ntNodeType);

            throw new GrammarErrorException(msg);
        }
Пример #10
0
        private void ExecuteReduceAction(ActionRecord action)
        {
            ParserState oldState = _currentState;
            int         popCnt   = action.PopCount;

            //Get new node's child nodes - these are nodes being popped from the stack
            AstNodeList childNodes = new AstNodeList();

            for (int i = 0; i < action.PopCount; i++)
            {
                AstNode child = Stack[Stack.Count - popCnt + i].Node;
                if (child.Term.IsSet(TermOptions.IsPunctuation))
                {
                    continue;
                }
                //Transient nodes - don't add them but add their childrent directly to grandparent
                if (child.Term.IsSet(TermOptions.IsTransient))
                {
                    foreach (AstNode grandChild in child.ChildNodes)
                    {
                        childNodes.Add(grandChild);
                    }
                    continue;
                }
                //Add normal child
                childNodes.Add(child);
            }

            //recover state, location and pop the stack
            SourceSpan newNodeSpan;

            if (popCnt == 0)
            {
                newNodeSpan = new SourceSpan(_currentToken.Location, 0);
            }
            else
            {
                SourceLocation firstPopLoc   = Stack[Stack.Count - popCnt].Node.Location;
                int            lastPopEndPos = Stack[Stack.Count - 1].Node.Span.EndPos;
                newNodeSpan   = new SourceSpan(firstPopLoc, lastPopEndPos - firstPopLoc.Position);
                _currentState = Stack[Stack.Count - popCnt].State;
                Stack.Pop(popCnt);
            }
            //Create new node
            AstNode node = CreateNode(action, newNodeSpan, childNodes);

            action.NonTerminal.OnNodeCreated(node);

            // Push node/current state into the stack
            Stack.Push(node, _currentState);
            //switch to new state
            ActionRecord gotoAction;

            if (_currentState.Actions.TryGetValue(action.NonTerminal.Key, out gotoAction))
            {
                _currentState = gotoAction.NewState;
            }
            else
            {
                //should never happen
                throw new CompilerException(string.Format("Cannot find transition for input {0}; state: {1}, popped state: {2}",
                                                          action.NonTerminal, oldState, _currentState));
            }
        }//method
Пример #11
0
 private void ExecuteShiftAction(ActionRecord action)
 {
     Stack.Push(_currentToken, _currentState);
     _currentState = action.NewState;
     NextToken();
 }
Пример #12
0
        }//method

        public AstNode Parse(CompilerContext context, IEnumerable <Token> tokenStream)
        {
            _context       = context;
            _caseSensitive = _context.Compiler.Grammar.CaseSensitive;
            Reset();
            _input = tokenStream.GetEnumerator();
            NextToken();
            while (true)
            {
                if (_currentState == Data.FinalState)
                {
                    AstNode result = Stack[0].Node;
                    //Check transient status
                    if (result.Term.IsSet(TermOptions.IsTransient) && result.ChildNodes.Count == 1)
                    {
                        result = result.ChildNodes[0];
                    }
                    Stack.Reset();
                    return(result);
                }
                //check for scammer error
                if (_currentToken.IsError())
                {
                    if (!Recover())
                    {
                        return(null);
                    }
                    continue;
                }
                //Get action
                ActionRecord action = GetCurrentAction();
                if (action == null)
                {
                    ReportParseError();
                    if (!Recover())
                    {
                        return(null); //did not recover
                    }
                    continue;
                }//action==null

                if (action.HasConflict())
                {
                    action = (ActionRecord)Data.Grammar.OnActionConflict(this, _currentToken, action);
                }
                this.OnActionSelected(_currentToken, action);
                switch (action.ActionType)
                {
                case ParserActionType.Operator:
                    if (GetActionTypeForOperation(_currentToken) == ParserActionType.Shift)
                    {
                        goto case ParserActionType.Shift;
                    }
                    else
                    {
                        goto case ParserActionType.Reduce;
                    }

                case ParserActionType.Shift:
                    ExecuteShiftAction(action);
                    break;

                case ParserActionType.Reduce:
                    ExecuteReduceAction(action);
                    break;
                } //switch
            }     //while
        }         //Parse