// ************************* //
        private Token match(Token.TokenType expectedTokenType)
        {
            Token matchedToken = lookAhead(1);

            if(lookAheadType(1) == expectedTokenType) {
                ConsumeCurrentToken();
            }
            else {
                throw new GrimmException(
                    "The code word \"" + lookAhead(1).getTokenString() + "\"" +
                    " doesn't match the expected (" + expectedTokenType + ")." +
                    " at line " +
                    lookAhead(1).LineNr +
                    " and position " +
                    lookAhead(1).LinePosition +
                    " in conversation '" +
                    _conversationName + "'"
                    );
            }

            return matchedToken;
        }
        private WaitDialogueNode VisitWaitDialogueNode(DialogueNode pPrevious)
        {
                        #if DEBUG_WRITE
            Console.WriteLine("WaitDialogueNode()");
                        #endif

            match(Token.TokenType.WAIT);

            WaitDialogueNode n = _dialogueRunner.Create <WaitDialogueNode>(_conversationName, _language, (_nodeCounter++) + " (start commando)");

            List <ExpressionDialogueNode> expressionNodes = new List <ExpressionDialogueNode>();

            bool hasEventListener = false;

            while (true)
            {
                if (lookAheadType(1) == Token.TokenType.NAME)
                {
                    string   expressionName = "";
                    string[] args           = VisitFunctionCall(out expressionName);

                    ExpressionDialogueNode expressionNode = _dialogueRunner.Create <ExpressionDialogueNode>(_conversationName, _language, (_nodeCounter++) + " (expression)");
                    expressionNode.expression = expressionName;
                    expressionNode.args       = args;
                    expressionNodes.Add(expressionNode);
                }
                else if (lookAheadType(1) == Token.TokenType.AND)
                {
                    ConsumeCurrentToken();
                }
                else if (lookAheadType(1) == Token.TokenType.LISTEN)
                {
                    if (hasEventListener)
                    {
                        throw new GrimmException(_conversationName + " already has a event listener attached to the wait statement on line " + lookAhead(1).LineNr);
                    }
                    ConsumeCurrentToken();
                    n.eventName      = match(Token.TokenType.NAME).getTokenString();
                    hasEventListener = true;
                                        #if DEBUG_WRITE
                    Console.WriteLine("This WaitDialogueNode has an event called " + n.eventName);
                                        #endif
                }
                else
                {
                    break;
                }
            }

            n.expressions = expressionNodes.ToArray();

            string handleName = "";
            if (lookAheadType(1) == Token.TokenType.BRACKET_LEFT)
            {
                match(Token.TokenType.BRACKET_LEFT);
                Token handleToken = match(Token.TokenType.NAME);
                handleName = handleToken.getTokenString();
                match(Token.TokenType.BRACKET_RIGHT);
            }

            n.handle = handleName;

            if (_loopStack.Count > 0)
            {
                // Add this listening dialogue node to the scope of the loop so that it is automatically removed when the loop ends
                n.scopeNode = _loopStack.Peek().name;
            }

                        #if DEBUG_WRITE
            Console.WriteLine("Added WaitDialogueNode() with name '" + n.name + "'");
                        #endif

            //if(!_dialogueRunner.HasExpression(expressionName)) {
            //throw new GrimmException("There is no '" + expressionName + "' expression registered in the dialogue runner");
            //}

            SilentDialogueNode silentEndNode = _dialogueRunner.Create <SilentDialogueNode>(_conversationName, _language, (_nodeCounter++).ToString() + "(silent stop node)");

            AllowLineBreak();

            if (lookAheadType(1) == Token.TokenType.BLOCK_BEGIN)
            {
                _loopStack.Push(n);

                ImmediateNode eventBranchStartNode = _dialogueRunner.Create <ImmediateNode>(_conversationName, _language, (_nodeCounter++).ToString() + "(waitBranchStartNode)");
                n.branchNode = eventBranchStartNode.name;
                n.hasBranch  = true;
                match(Token.TokenType.BLOCK_BEGIN);
                Nodes(eventBranchStartNode, silentEndNode);
                match(Token.TokenType.BLOCK_END);

                _loopStack.Pop();
            }
            else
            {
                                #if DEBUG_WRITE
                Console.WriteLine("this wait dialogue node had no body");
                                #endif
            }

            AddLinkFromPreviousNode(pPrevious, n);

            return(n);
        }
        private void ConsumeCurrentToken()
        {
            Token nextToken;

            if (_nextTokenIndex < _tokens.Count) {
                nextToken = _tokens[_nextTokenIndex];
                _nextTokenIndex++;
            }
            else {
                nextToken = new Token(Token.TokenType.EOF, "<EOF>");
            }

            _lookahead[_lookaheadIndex] = nextToken;
            _lookaheadIndex = (_lookaheadIndex + 1) % k;
        }
        DialogueNode VisitListeningDialogueNode(DialogueNode pPrevious)
        {
                        #if DEBUG_WRITE
            Console.WriteLine("VisitListeningDialogueNode()");
                        #endif

            match(Token.TokenType.LISTEN);

            string eventName = GetAStringFromNextToken(false, false);

            string handleName = "";
            if (lookAheadType(1) == Token.TokenType.BRACKET_LEFT)
            {
                match(Token.TokenType.BRACKET_LEFT);
                Token handleToken = match(Token.TokenType.NAME);
                handleName = handleToken.getTokenString();
                match(Token.TokenType.BRACKET_RIGHT);
            }
            else if (
                (lookAheadType(1) != Token.TokenType.EOF) &&
                (lookAheadType(1) != Token.TokenType.NEW_LINE) &&
                (lookAheadType(1) != Token.TokenType.BLOCK_BEGIN))
            {
                throw new GrimmException("Can't follow LISTEN statement with token of type " + lookAheadType(1) + " at line " + lookAhead(1).LineNr + " and position " + lookAhead(1).LinePosition + " in " + _conversationName);
            }

            ListeningDialogueNode n = _dialogueRunner.Create <ListeningDialogueNode>(_conversationName, _language, (_nodeCounter++).ToString() + "(event listener)");
            n.eventName = eventName;
            n.handle    = handleName;

            if (_loopStack.Count > 0)
            {
                // Add this listening dialogue node to the scope of the loop so that it is automatically removed as a listener when the loop ends
                n.scopeNode = _loopStack.Peek().name;
            }
            SilentDialogueNode silentNode = _dialogueRunner.Create <SilentDialogueNode>(_conversationName, _language, (_nodeCounter++).ToString() + "(silent stop node)");

            AllowLineBreak();

            if (lookAheadType(1) == Token.TokenType.BLOCK_BEGIN)
            {
                _loopStack.Push(n);

                ImmediateNode eventBranchStartNode = _dialogueRunner.Create <ImmediateNode>(_conversationName, _language, (_nodeCounter++).ToString() + "(eventBranchStartNode)");
                n.branchNode = eventBranchStartNode.name;
                n.hasBranch  = true;
                match(Token.TokenType.BLOCK_BEGIN);
                Nodes(eventBranchStartNode, silentNode);
                match(Token.TokenType.BLOCK_END);

                _loopStack.Pop();
            }
            else
            {
                                #if DEBUG_WRITE
                Console.WriteLine("this listening dialogue node had no body");
                                #endif
            }

            AddLinkFromPreviousNode(pPrevious, n);
            return(n);
        }