private void DequeueIdentifierUsage(Node parent, string error)
        {
            Token token = Dequeue();

            if (token?.Type == NodeType.Identifier)
            {
                Identifier   identifier;
                SymbolLookup lookup = symbolTable.Get(token.Value);
                if (lookup == null)
                {
                    identifier = new Identifier(token.Value, Peek() == "." ? IdentifierKind.Class : IdentifierKind.Subroutine, false);
                }
                else
                {
                    identifier           = new Identifier(lookup.Name, lookup.Kind, false, lookup.Number);
                    identifier.ClassType = lookup.ClassType;
                }
                parent.AddChild(identifier);
                if (Peek() == "[")
                {
                    DequeueSymbol(parent, "[");
                    parent.AddChild(ParseExpression());
                    DequeueSymbol(parent, "]");
                }
            }
            else
            {
                string suffix = token == null ? ", reached end of file instead" : $", got {token} instead";
                throw new ApplicationException(error + suffix);
            }
        }
        public SymbolLookup Add(string name, IdentifierKind kind, string classType)
        {
            SymbolLookup symbol = null;

            if (IsFieldOrStatic(kind))
            {
                int number = classSymbols.Count(s => s.Kind == kind);
                symbol = new SymbolLookup {
                    Name = name, Kind = kind, Number = number, ClassType = classType
                };
                classSymbols.Add(symbol);
            }
            if (IsArgumentOrVar(kind))
            {
                int number = subroutineSymbols.Count(s => s.Kind == kind);
                if (isMethod && kind == IdentifierKind.Argument)
                {
                    number++;
                }
                symbol = new SymbolLookup {
                    Name = name, Kind = kind, Number = number, ClassType = classType
                };
                subroutineSymbols.Add(symbol);
            }
            return(symbol);
        }
        private void DequeueIdentifierDeclaration(Node parent, IdentifierKind kind, string classType, string error)
        {
            Token token = Dequeue();

            if (token?.Type == NodeType.Identifier)
            {
                Identifier identifier;
                if (SymbolTable.IsClassOrSubroutine(kind))
                {
                    identifier = new Identifier(token.Value, kind, true);
                }
                else
                {
                    SymbolLookup symbolLookup = symbolTable.Add(token.Value, kind, classType);
                    if (symbolLookup != null)
                    {
                        identifier = new Identifier(symbolLookup.Name, symbolLookup.Kind, true, symbolLookup.Number);
                    }
                    else
                    {
                        identifier = new Identifier(token.Value, IdentifierKind.Subroutine, true);
                    }
                }
                identifier.ClassType = classType;
                parent.AddChild(identifier);
                if (Peek() == "[")
                {
                    DequeueSymbol(parent, "[");
                    parent.AddChild(ParseExpression());
                    DequeueSymbol(parent, "]");
                }
            }
            else
            {
                string suffix = token == null ? ", reached end of file instead" : $", got {token} instead";
                throw new ApplicationException(error + suffix);
            }
        }
        public SymbolLookup Get(string name)
        {
            SymbolLookup subroutineSymbol = subroutineSymbols.SingleOrDefault(s => s.Name == name);

            return(subroutineSymbol ?? classSymbols.SingleOrDefault(s => s.Name == name));
        }