private void ValidarTiposAtribuicao()
        {
            TipoItemTs tipoVar;

            var indexAtribuicao = IndexAtual;

            while (Tokens[indexAtribuicao].Tipo != TipoToken.SimboloAtribuicao)
            {
                indexAtribuicao--;
            }

            indexAtribuicao--;

            switch (Tokens[indexAtribuicao].Tipo)
            {
            case TipoToken.Identificador:
                tipoVar = TabelaDeSimbolos.Find(Tokens[indexAtribuicao].Cadeia, EscopoStack.Peek()).Tipo;
                break;

            case TipoToken.NumeroReal:
                tipoVar = TipoItemTs.NumeroReal;
                break;

            default:
                tipoVar = TipoItemTs.NumeroInteiro;
                break;
            }

            if (TipoItensExpressao.Any(x => x != tipoVar))
            {
                throw new CompiladorException(
                          $"Atribuição inválida, era esperado um valor do tipo {tipoVar.ToString()}\nLinha: {Tokens[indexAtribuicao].Linha}");
            }
        }
        private void ValidarParametros(ItemTs procedure)
        {
            //Validar argumentos procedure

            var i = IndexAtual;

            var tipoParametros = new List <TipoParametro>();

            while (Tokens[i].Tipo != TipoToken.SimboloAbreParenteses)
            {
                if (Tokens[i].Tipo == TipoToken.Identificador)
                {
                    var parametro = TabelaDeSimbolos.Find(Tokens[i].Cadeia, EscopoStack.Peek());
                    tipoParametros.Add(parametro.Tipo == TipoItemTs.NumeroInteiro
                        ? TipoParametro.NumeroInteiro
                        : TipoParametro.NumeroReal);
                }

                i--;
            }

            if (tipoParametros.Count != procedure.Parametros.Count)
            {
                throw new CompiladorException($"Quantidade errada de parametros\nLinha: {Tokens[i].Linha}");
            }

            for (int j = 0; j < tipoParametros.Count - 1; j++)
            {
                if (tipoParametros[j] != procedure.Parametros[j].Tipo)
                {
                    throw new CompiladorException(
                              $"Parametro com tipo diferente do esperado, encontrou {tipoParametros[j].ToString()} mas esperava {procedure.Parametros[j].Tipo.ToString()}\nLinha: {Tokens[i].Linha}");
                }
            }
        }
        private void ValidarVariavel()
        {
            var i = 0;

            while (new List <string>()
            {
                nameof(MaisVar), nameof(Variaveis)
            }.Contains(CallStack.ElementAt(i)))
            {
                i++;
            }

            var callerName = CallStack.ElementAt(i);

            if (callerName == nameof(DcV) || callerName == nameof(ListaPar))
            {
                TabelaDeSimbolos.TryAddNewItem(new ItemTs
                {
                    Cadeia = Tokens[IndexAtual].Cadeia, Escopo = EscopoStack.Peek(), Tipo = TipoItemTs.Desconhecido,
                    Linha  = Tokens[IndexAtual].Linha
                });

                GeradorCodigoHipo.AreaDeCodigo.Add(InstrucoesMaquinaHipo.ALME + " 1");
            }
            else
            {
                TabelaDeSimbolos.VerificarSeVariavelJaFoiDeclarada(new ItemTs
                {
                    Cadeia = Tokens[IndexAtual].Cadeia, Escopo = EscopoStack.Peek(), Tipo = TipoItemTs.Desconhecido
                });
            }
        }
        private void Programa()
        {
            CallStack.Push(nameof(Programa));

            UltimoIdex = Tokens.Count - 1;
            IndexAtual = 0;

            if (Tokens[IndexAtual].Tipo != TipoToken.ReservadoProgram)
            {
                ThrowCompiladorException(Tokens[IndexAtual]);
            }
            IndexAtual++;

            if (Tokens[IndexAtual].Tipo != TipoToken.Identificador)
            {
                ThrowCompiladorException(Tokens[IndexAtual]);
            }

            EscopoStack.Push($"Global - {Tokens[IndexAtual].Cadeia}");

            IndexAtual++;

            GeradorCodigoHipo.AreaDeCodigo.Add(InstrucoesMaquinaHipo.INPP.ToString());
            Corpo();

            if (!IndexInRange() || Tokens[IndexAtual].Tipo != TipoToken.SimboloPonto)
            {
                throw new CompiladorException($"Erro sintático: Faltando simbolo '.' no final do programa \n linha: {Tokens[IndexAtual-1].Linha}");
            }

            GeradorCodigoHipo.AreaDeCodigo.Add(InstrucoesMaquinaHipo.PARA.ToString());
            CallStack.Pop();
        }
        private void DcP()
        {
            CallStack.Push(nameof(DcP));

            if (Tokens[IndexAtual].Tipo == TipoToken.ReservadoProcedure)
            {
                IndexAtual++;
                if (Tokens[IndexAtual].Tipo == TipoToken.Identificador)
                {
                    var procedure = new ItemTs
                    {
                        Cadeia     = Tokens[IndexAtual].Cadeia,
                        Escopo     = EscopoStack.Peek(),
                        Tipo       = TipoItemTs.Procedimento,
                        Linha      = Tokens[IndexAtual].Linha,
                        Parametros = new List <Parametro>()
                    };

                    EscopoStack.Push(Tokens[IndexAtual].Cadeia);

                    IndexAtual++;
                    Parametros();

                    AddParametrosNaProcedure(procedure);

                    TabelaDeSimbolos.TryAddNewItem(procedure);

                    CorpoP();

                    EscopoStack.Pop();
                }
                else
                {
                    ThrowCompiladorException(Tokens[IndexAtual]);
                }
            }
            else
            {
                ThrowCompiladorException(Tokens[IndexAtual]);
            }

            CallStack.Pop();
        }
        private void Fator()
        {
            CallStack.Push(nameof(Fator));

            switch (Tokens[IndexAtual].Tipo)
            {
            case TipoToken.Identificador:
                ValidarVariavel();
                var simboloTs = TabelaDeSimbolos.Find(Tokens[IndexAtual].Cadeia, EscopoStack.Peek());
                TipoItensExpressao.Add(simboloTs.Tipo);
                IndexAtual++;
                break;

            case TipoToken.NumeroInteiro:
                IndexAtual++;
                TipoItensExpressao.Add(TipoItemTs.NumeroInteiro);
                break;

            case TipoToken.NumeroReal:
                IndexAtual++;
                TipoItensExpressao.Add(TipoItemTs.NumeroReal);
                break;

            case TipoToken.SimboloAbreParenteses:
                IndexAtual++;

                Expressao();

                if (Tokens[IndexAtual].Tipo == TipoToken.SimboloFechaParenteses)
                {
                    IndexAtual++;
                }
                else
                {
                    ThrowCompiladorException(Tokens[IndexAtual]);
                }
                break;
            }

            CallStack.Pop();
        }
        private void Comando()
        {
            CallStack.Push(nameof(Comando));

            switch (Tokens[IndexAtual].Tipo)
            {
            case TipoToken.ReservadoRead:
                IndexAtual++;
                if (Tokens[IndexAtual].Tipo == TipoToken.SimboloAbreParenteses)
                {
                    IndexAtual++;
                    Variaveis();
                    if (Tokens[IndexAtual].Tipo == TipoToken.SimboloFechaParenteses)
                    {
                        IndexAtual++;
                    }
                    else
                    {
                        ThrowCompiladorException(Tokens[IndexAtual]);
                    }
                }
                else
                {
                    ThrowCompiladorException(Tokens[IndexAtual]);
                }

                GeradorCodigoHipo.AreaDeCodigo.Add(InstrucoesMaquinaHipo.LEIT.ToString());
                //Todo implementar endereço real dos items em AreaDeDados
                GeradorCodigoHipo.AreaDeCodigo.Add(InstrucoesMaquinaHipo.ARMZ + " " + GeradorCodigoHipo.AreaDeDados.Count);
                break;

            case TipoToken.ReservadoWrite:
                IndexAtual++;
                if (Tokens[IndexAtual].Tipo == TipoToken.SimboloAbreParenteses)
                {
                    IndexAtual++;
                    Variaveis();
                    if (Tokens[IndexAtual].Tipo == TipoToken.SimboloFechaParenteses)
                    {
                        IndexAtual++;
                    }
                    else
                    {
                        ThrowCompiladorException(Tokens[IndexAtual]);
                    }
                }
                else
                {
                    ThrowCompiladorException(Tokens[IndexAtual]);
                }

                break;

            case TipoToken.ReservadoWhile:
                IndexAtual++;

                Condicao();
                GeradorCodigoHipo.AreaDeCodigo.Add(InstrucoesMaquinaHipo.CRVL + " 1");
                GeradorCodigoHipo.AreaDeCodigo.Add(InstrucoesMaquinaHipo.CRVL + " 0");

                /*
                 * var i = IndexAtual;
                 * while (Tokens[i].Tipo != TipoToken.ReservadoWhile)
                 * {
                 *
                 *  i--;
                 * }
                 */

                if (Tokens[IndexAtual].Tipo == TipoToken.ReservadoDo)
                {
                    IndexAtual++;
                    Comandos();
                    if (Tokens[IndexAtual].Tipo == TipoToken.SimboloCifrao)
                    {
                        IndexAtual++;
                    }
                    else
                    {
                        ThrowCompiladorException(Tokens[IndexAtual]);
                    }
                }
                else
                {
                    ThrowCompiladorException(Tokens[IndexAtual]);
                }

                break;

            case TipoToken.ReservadoIf:
                IndexAtual++;

                Condicao();
                if (Tokens[IndexAtual].Tipo == TipoToken.ReservadoThen)
                {
                    IndexAtual++;
                    Comandos();
                    Pfalsa();
                    if (Tokens[IndexAtual].Tipo == TipoToken.SimboloCifrao)
                    {
                        IndexAtual++;
                    }
                    else
                    {
                        ThrowCompiladorException(Tokens[IndexAtual]);
                    }
                }
                else
                {
                    ThrowCompiladorException(Tokens[IndexAtual]);
                }

                break;

            case TipoToken.Identificador:

                var  procedure   = TabelaDeSimbolos.Find(Tokens[IndexAtual].Cadeia, EscopoStack.Peek(), true);
                bool isProcedure = procedure != null;

                if (procedure == null && TabelaDeSimbolos.Find(Tokens[IndexAtual].Cadeia, EscopoStack.Peek()) == null)
                {
                    throw new CompiladorException($"Procedure {Tokens[IndexAtual].Cadeia} não declarada\nLinha: {Tokens[IndexAtual].Linha}");
                }

                IndexAtual++;
                RestoIdent();

                if (isProcedure)
                {
                    ValidarParametros(procedure);
                }

                break;

            default:
                ThrowCompiladorException(Tokens[IndexAtual]);
                break;
            }

            CallStack.Pop();
        }