/*
         * Returns the identifier for the specified symbol defined in
         * the specified scope or in any scope above it. Returns null
         * if this symbol does not have a corresponding identifier.
         */

        private static JavaScriptIdentifier GetIdentifier(string symbol,
                                                          ScriptOrFunctionScope scope)
        {
            while (scope != null)
            {
                JavaScriptIdentifier identifier = scope.GetIdentifier(symbol);
                if (identifier != null)
                {
                    return identifier;
                }

                scope = scope.ParentScope;
            }

            return null;
        }
        private void ParseScope(ScriptOrFunctionScope scope)
        {
            string symbol;
            JavaScriptToken token;
            JavaScriptIdentifier identifier;


            int length = _tokens.Count;

            EnterScope(scope);

            while (_offset < length)
            {
                token = ConsumeToken();

                switch (token.TokenType)
                {
                    case Token.VAR:
                    case Token.CONST:
                        if (token.TokenType == Token.VAR)
                        {
                            if (_mode == BUILDING_SYMBOL_TREE &&
                                scope.VarCount++ > 1)
                            {
                                Warn("Try to use a single 'var' statement per scope.", true);
                            }
                        }

                        // The var keyword is followed by at least one symbol name.
                        // If several symbols follow, they are comma separated.
                        //for (; ;)
                        while (true)
                        {
                            token = ConsumeToken();
                            if (token.TokenType != Token.NAME)
                            {
                                throw new InvalidOperationException();
                            }

                            if (_mode == BUILDING_SYMBOL_TREE)
                            {
                                symbol = token.Value;
                                if (scope.GetIdentifier(symbol) == null)
                                {
                                    scope.DeclareIdentifier(symbol);
                                }
                                else
                                {
                                    Warn(
                                        "The variable " + symbol + " has already been declared in the same scope...",
                                        true);
                                }
                            }

                            token = GetToken(0);
                            if (token.TokenType != Token.SEMI &&
                                token.TokenType != Token.ASSIGN &&
                                token.TokenType != Token.COMMA &&
                                token.TokenType != Token.IN)
                            {
                                throw new InvalidOperationException();
                            }

                            if (token.TokenType == Token.IN)
                            {
                                break;
                            }

                            ParseExpression();
                            token = GetToken(-1);
                            if (token.TokenType == Token.SEMI)
                            {
                                break;
                            }
                        }

                        break;

                    case Token.FUNCTION:
                        ParseFunctionDeclaration();
                        break;

                    case Token.LC:
                        _braceNesting++;
                        break;

                    case Token.RC:
                        _braceNesting--;
                        if (_braceNesting < scope.BraceNesting)
                        {
                            throw new InvalidOperationException();
                        }

                        if (_braceNesting == scope.BraceNesting)
                        {
                            LeaveCurrentScope();
                            return;
                        }

                        break;

                    case Token.WITH:
                        if (_mode == BUILDING_SYMBOL_TREE)
                        {
                            // Inside a 'with' block, it is impossible to figure out
                            // statically whether a symbol is a local variable or an
                            // object member. As a consequence, the only thing we can
                            // do is turn the obfuscation off for the highest scope
                            // containing the 'with' block.
                            ProtectScopeFromObfuscation(scope);
                            Warn(
                                "Using 'with' is not recommended." +
                                (_munge ? " Moreover, using 'with' reduces the level of compression!" : ""), true);
                        }
                        break;

                    case Token.CATCH:
                        ParseCatch();
                        break;

                    case Token.CONDCOMMENT:
                        if (_mode == BUILDING_SYMBOL_TREE)
                        {
                            ProtectScopeFromObfuscation(scope);
                            Warn(
                                "Using JScript conditional comments is not recommended." +
                                (_munge
                                     ? " Moreover, using JScript conditional comments reduces the level of compression."
                                     : ""), true);
                        }
                        break;

                    case Token.NAME:
                        symbol = token.Value;

                        if (_mode == BUILDING_SYMBOL_TREE)
                        {
                            if (!_isEvalIgnored &&
                                symbol.Equals("eval", StringComparison.OrdinalIgnoreCase))
                            {
                                ProtectScopeFromObfuscation(scope);
                                Warn(
                                    "Using 'eval' is not recommended." +
                                    (_munge ? " Moreover, using 'eval' reduces the level of compression!" : ""),
                                    true);
                            }
                        }
                        else if (_mode == CHECKING_SYMBOL_TREE)
                        {
                            if ((_offset < 2 ||
                                 GetToken(-2).TokenType != Token.DOT) &&
                                GetToken(0).TokenType != Token.OBJECTLIT)
                            {
                                identifier = GetIdentifier(symbol, scope);

                                if (identifier == null)
                                {
                                    if (symbol.Length <= 3 &&
                                        !_builtin.Contains(symbol))
                                    {
                                        // Here, we found an undeclared and un-namespaced symbol that is
                                        // 3 characters or less in length. Declare it in the global scope.
                                        // We don't need to declare longer symbols since they won't cause
                                        // any conflict with other munged symbols.
                                        _globalScope.DeclareIdentifier(symbol);
                                        Warn("Found an undeclared symbol: " + symbol, true);
                                    }
                                }
                                else
                                {
                                    identifier.RefCount++;
                                }
                            }
                        }

                        break;
                }
            }
        }