Repository: DesignLiquido/delegua
Pull request #782 (2025-06-24 22:57:25)

Tradução Tenda para Delégua
Resolve: https://github.com/DesignLiquido/delegua/issues/781

PR ainda não esta pronta.

github-actions[bot]: <!-- jest coverage report action for options with hash 781087021f8e6c43aac1e668f4520603 -->

## Coverage report 


| <div title="Status of coverage:&#10; 🟢 - ok&#10; 🟡 - slightly more than threshold&#10; 🔴 - under the threshold">St.<sup>:grey_question:</sup></div> | Category | Percentage | Covered / Total |
| :-: | :- | :- | :-: |
| 🟡 | Statements | <div title="Base coverage is: 72.71%">65.7% (-7.01% 🔻)</div> | 7136/10862 |
| 🔴 | Branches | <div title="Base coverage is: 63.08%">56.12% (-6.97% 🔻)</div> | 2271/4047 |
| 🔴 | Functions | <div title="Base coverage is: 62.08%">59.57% (-2.52% 🔻)</div> | 1015/1704 |
| 🟡 | Lines | <div title="Base coverage is: 73.24%">66.09% (-7.15% 🔻)</div> | 6982/10564 |

<details><summary>Show new covered files 🐣</summary>
<br/>

| <div title="Status of coverage:&#10; 🟢 - ok&#10; 🟡 - slightly more than threshold&#10; 🔴 - under the threshold">St.<sup>:grey_question:</sup></div> | File | Statements | Branches | Functions | Lines |
| :-: | :- | :- | :- | :- | :- |
| 🔴 | <div title="lexador/dialetos/lexador-tenda.ts">`...` / lexador-tenda.ts</div> | 49.29% | 45.92% | 84.21% | 49.27% |
| 🟢 | <div title="lexador/dialetos/palavras-reservadas/tenda.ts">`...` / tenda.ts</div> | 100% | 100% | 100% | 100% |
| 🟢 | <div title="tipos-de-simbolos/tenda.ts">`...` / tenda.ts</div> | 100% | 100% | 100% | 100% |
| 🔴 | <div title="avaliador-sintatico/dialetos/avaliador-sintatico-tenda.ts">`...` / avaliador-sintatico-tenda.ts</div> | 22.16% | 9% | 34.72% | 22.36% |
| 🔴 | <div title="tradutores/tradudor-reverso-tenda.ts">`...` / tradudor-reverso-tenda.ts</div> | 9.77% | 5.59% | 14.04% | 10.03% |

</details>


## Test suite run success
588 tests passing in 36 suites.

<p align="right">Report generated by <a href="https://github.com/ArtiomTr/jest-coverage-report-action">🧪jest coverage report action</a> from b50ca0228c98d67d8650f44decb61f9e4011e079</p>
<!-- Sticky Pull Request Comment -->

Patch:
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 1f20cde2..6b18f4d2 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -135,6 +135,23 @@
             "console": "integratedTerminal",
             "internalConsoleOptions": "neverOpen"
         },
+        {
+            "name": "Testes unitários - Tradutor Tenda para Delégua",
+            "type": "node",
+            "request": "launch",
+            "runtimeArgs": [
+                "--inspect-brk",
+                "${workspaceRoot}/node_modules/jest/bin/jest.js",
+                "tradutor-reverso-tenda.test.ts",
+                "--runInBand"
+            ],
+            "skipFiles": [
+                "<node_internals>/**",
+                "node_modules/**"
+            ],
+            "console": "integratedTerminal",
+            "internalConsoleOptions": "neverOpen"
+        },
         {
             "name": "Testes unitários - Tradutor Portugol IPT para Delégua",
             "type": "node",
diff --git a/fontes/avaliador-sintatico/avaliador-sintatico-base.ts b/fontes/avaliador-sintatico/avaliador-sintatico-base.ts
index 47723f65..ef6c1183 100644
--- a/fontes/avaliador-sintatico/avaliador-sintatico-base.ts
+++ b/fontes/avaliador-sintatico/avaliador-sintatico-base.ts
@@ -105,9 +105,7 @@ export abstract class AvaliadorSintaticoBase
     protected abstract chamar(): Construto;
     protected abstract corpoDaFuncao(tipo: string): FuncaoConstruto;
     protected abstract declaracaoEnquanto(): Enquanto;
-    protected abstract declaracaoEscolha(): Escolha;
     protected abstract declaracaoEscreva(): Escreva;
-    protected abstract declaracaoFazer(): Fazer;
     protected abstract declaracaoPara(): Para | ParaCada;
     protected abstract declaracaoSe(): Se;
     protected abstract expressaoLeia(): Leia;
diff --git a/fontes/avaliador-sintatico/avaliador-sintatico.ts b/fontes/avaliador-sintatico/avaliador-sintatico.ts
index 4313bae0..ce1d8d03 100644
--- a/fontes/avaliador-sintatico/avaliador-sintatico.ts
+++ b/fontes/avaliador-sintatico/avaliador-sintatico.ts
@@ -1320,7 +1320,7 @@ export class AvaliadorSintatico
         }
     }
 
-    override declaracaoEscolha(): Escolha {
+    protected declaracaoEscolha(): Escolha {
         try {
             this.blocos += 1;
 
@@ -1447,7 +1447,7 @@ export class AvaliadorSintatico
         return new Falhar(simboloFalha, this.declaracaoExpressao().expressao);
     }
 
-    override declaracaoFazer(): Fazer {
+    protected declaracaoFazer(): Fazer {
         const simboloFazer: SimboloInterface = this.simbolos[this.atual - 1];
         try {
             this.blocos += 1;
@@ -1526,9 +1526,14 @@ export class AvaliadorSintatico
             );
         }
 
+        let tipoVariavelIteracao = 'qualquer';
+        if (tipoVetor.endsWith('[]')) {
+            tipoVariavelIteracao = tipoVetor.slice(0, -2);
+        }
+
         this.pilhaEscopos.definirInformacoesVariavel(
-            nomeVariavelIteracao.lexema,
-            new InformacaoVariavelOuConstante(nomeVariavelIteracao.lexema, tipoVetor.slice(0, -2))
+            nomeVariavelIteracao.lexema, 
+            new InformacaoVariavelOuConstante(nomeVariavelIteracao.lexema, tipoVariavelIteracao)
         );
         // TODO: Talvez não seja uma ideia melhor chamar o método de `Bloco` aqui?
         const corpo: Bloco = this.resolverDeclaracao() as Bloco;
diff --git a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.ts b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.ts
new file mode 100644
index 00000000..4dec0ad2
--- /dev/null
+++ b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.ts
@@ -0,0 +1,1691 @@
+import hrtime from 'browser-process-hrtime';
+
+import {
+    AcessoIndiceVariavel,
+    AcessoMetodo,
+    AcessoMetodoOuPropriedade,
+    AcessoPropriedade,
+    Agrupamento,
+    ArgumentoReferenciaFuncao,
+    AtribuicaoPorIndice,
+    Atribuir,
+    Binario,
+    Chamada,
+    Construto,
+    DefinirValor,
+    Dicionario,
+    ExpressaoRegular,
+    FimPara,
+    FuncaoConstruto,
+    Leia,
+    Literal,
+    Logico,
+    ReferenciaFuncao,
+    Super,
+    Unario,
+    Variavel,
+    Vetor,
+} from '../../construtos';
+import { ParametroInterface, SimboloInterface } from '../../interfaces';
+
+import { ErroAvaliadorSintatico } from './../erro-avaliador-sintatico';
+
+import { SeletorTuplas, Tupla } from '../../construtos/tuplas';
+import {
+    Bloco,
+    Comentario,
+    Continua,
+    Declaracao,
+    Enquanto,
+    Escreva,
+    Expressao,
+    FuncaoDeclaracao,
+    Para,
+    ParaCada,
+    Retorna,
+    Se,
+    Sustar,
+    Var,
+} from '../../declaracoes';
+import { RetornoAvaliadorSintatico } from '../../interfaces/retornos/retorno-avaliador-sintatico';
+import { RetornoLexador } from '../../interfaces/retornos/retorno-lexador';
+import { TipoDadosElementar } from '../../tipo-dados-elementar';
+import { AvaliadorSintaticoBase } from '../avaliador-sintatico-base';
+import { inferirTipoVariavel, tipoInferenciaParaTipoDadosElementar } from '../../inferenciador';
+import { TipoInferencia } from '../../inferenciador';
+import { PilhaEscopos } from './../pilha-escopos';
+import { InformacaoEscopo } from './../informacao-escopo';
+import { InformacaoVariavelOuConstante } from '../../informacao-variavel-ou-constante';
+import { Simbolo } from '../../lexador/simbolo';
+
+import tipoDeDadosDelegua from '../../tipos-de-dados/delegua';
+import tiposDeSimbolos from '../../tipos-de-simbolos/tenda';
+
+import primitivasDicionario from '../../bibliotecas/primitivas-dicionario';
+import primitivasNumero from '../../bibliotecas/primitivas-numero';
+import primitivasTexto from '../../bibliotecas/primitivas-texto';
+import primitivasVetor from '../../bibliotecas/primitivas-vetor';
+
+// Será usado para forçar tipagem em construtos e em algumas funções internas.
+type TipoDeSimboloDelegua = (typeof tiposDeSimbolos)[keyof typeof tiposDeSimbolos];
+
+/**
+ * Este avaliador sintático emite todos os símbolos de Tenda. No entanto, nem todo
+ * símbolo emitido aqui pode ser interpretado por este núcleo, já que Tenda tem 
+ * Rust como base, e várias de suas funções requerem interface com um sistema operacional.
+ * Outros pacotes do ecossistema de Delégua, como `delegua-node` poderão lidar com
+ * todas as funcionalidades de Tenda.
+ */
+export class AvaliadorSintaticoTenda extends AvaliadorSintaticoBase {
+    simbolos: SimboloInterface[];
+    erros: ErroAvaliadorSintatico[];
+    tiposDefinidosEmCodigo: { [key: string]: Declaracao };
+    pilhaEscopos: PilhaEscopos;
+    tiposDeFerramentasExternas: { [key: string]: { [key: string]: string } };
+    primitivasConhecidas: { [key: string]: InformacaoVariavelOuConstante };
+
+    hashArquivo: number;
+    atual: number;
+    blocos: number;
+    performance: boolean;
+    superclasseAtual: string | undefined;
+
+    constructor(performance = false) {
+        super();
+        this.hashArquivo = 0;
+        this.atual = 0;
+        this.blocos = 0;
+        this.erros = [];
+        this.performance = performance;
+        this.tiposDefinidosEmCodigo = {};
+        this.tiposDeFerramentasExternas = {};
+        this.primitivasConhecidas = {};
+
+        for (const [nomePrimitivaDicionario, dadosPrimitiva] of Object.entries(primitivasDicionario)) {
+            this.primitivasConhecidas[nomePrimitivaDicionario] = new InformacaoVariavelOuConstante(
+                nomePrimitivaDicionario, 
+                'dicionário',
+                dadosPrimitiva.argumentos
+            );
+        }
+
+        for (const [nomePrimitivaNumero, dadosPrimitiva] of Object.entries(primitivasNumero)) {
+            this.primitivasConhecidas[nomePrimitivaNumero] = new InformacaoVariavelOuConstante(
+                nomePrimitivaNumero, 
+                'número',
+                dadosPrimitiva.argumentos
+            );
+        }
+
+        for (const [nomePrimitivaTexto, dadosPrimitiva] of Object.entries(primitivasTexto)) {
+            this.primitivasConhecidas[nomePrimitivaTexto] = new InformacaoVariavelOuConstante(
+                nomePrimitivaTexto, 
+                'texto',
+                dadosPrimitiva.argumentos
+            );
+        }
+
+        for (const [nomePrimitivaVetor, dadosPrimitiva] of Object.entries(primitivasVetor)) {
+            this.primitivasConhecidas[nomePrimitivaVetor] = new InformacaoVariavelOuConstante(
+                nomePrimitivaVetor, 
+                'vetor',
+                dadosPrimitiva.argumentos
+            );
+        }
+
+        // TODO: Por enquanto não há necessidade de validar argumentos aqui, mas isso pode mudar no futuro.
+        this.primitivasConhecidas['inteiro'] = new InformacaoVariavelOuConstante('inteiro', 'inteiro');
+        this.primitivasConhecidas['numero'] = new InformacaoVariavelOuConstante('numero', 'número');
+        this.primitivasConhecidas['número'] = new InformacaoVariavelOuConstante('número', 'número');
+        this.primitivasConhecidas['texto'] = new InformacaoVariavelOuConstante('texto', 'texto');
+
+        this.pilhaEscopos = new PilhaEscopos();
+    }
+
+    protected verificarDefinicaoTipoAtual(): string {
+        const tipos = [...Object.values(tipoDeDadosDelegua)];
+
+        if (this.simbolos[this.atual].lexema in this.tiposDefinidosEmCodigo) {
+            return this.simbolos[this.atual].lexema;
+        }
+
+        const lexemaElementar = this.simbolos[this.atual].lexema.toLowerCase();
+        const tipoElementarResolvido = tipos.find((tipo) => tipo === lexemaElementar);
+        if (!tipoElementarResolvido) {
+            throw this.erro(
+                this.simbolos[this.atual],
+                `Tipo de dados desconhecido: '${this.simbolos[this.atual].lexema}'.`
+            );
+        }
+
+        if (this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_ESQUERDO)) {
+            const tiposVetores = ['inteiro[]', 'numero[]', 'número[]', 'qualquer[]', 'real[]', 'texto[]'];
+            this.avancarEDevolverAnterior();
+
+            if (!this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_DIREITO)) {
+                throw this.erro(
+                    this.simbolos[this.atual],
+                    `Esperado símbolo de fechamento do vetor: ']'. Atual: ${this.simbolos[this.atual].lexema}`
+                );
+            }
+
+            const tipoVetor = tiposVetores.find((tipo) => tipo === `${lexemaElementar}[]`);
+            this.avancarEDevolverAnterior();
+            return tipoVetor as TipoDadosElementar;
+        }
+
+        return tipoElementarResolvido as TipoDadosElementar;
+    }
+
+    protected obterChaveDicionario(): Construto {
+        switch (this.simbolos[this.atual].tipo) {
+            case tiposDeSimbolos.NUMERO:
+            case tiposDeSimbolos.TEXTO:
+            case tiposDeSimbolos.FALSO:
+            case tiposDeSimbolos.VERDADEIRO:
+                return this.primario();
+            case tiposDeSimbolos.IDENTIFICADOR:
+                const simboloIdentificador: SimboloInterface = this.avancarEDevolverAnterior();
+                let tipoOperando: string;
+                if (simboloIdentificador.lexema in this.tiposDefinidosEmCodigo) {
+                    tipoOperando = simboloIdentificador.lexema;
+                } else {
+                    tipoOperando = this.pilhaEscopos.obterTipoVariavelPorNome(simboloIdentificador.lexema);
+                }
+
+                if (!['numero', 'número', 'texto', 'lógico'].includes(tipoOperando)) {
+                    throw this.erro(
+                        simboloIdentificador,
+                        `Tipo ${tipoOperando} de identificador ${simboloIdentificador.lexema} não é válido como chave de dicionário.`
+                    );
+                }
+
+                return new Variavel(this.hashArquivo, simboloIdentificador, tipoOperando);
+            case tiposDeSimbolos.COLCHETE_ESQUERDO:
+                this.avancarEDevolverAnterior();
+                if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO)) {
+                    return this.construtoTupla();
+                }
+
+                throw this.erro(
+                    this.simbolos[this.atual],
+                    `Esperado parêntese esquerdo após colchete esquerdo para definição de chave de dicionário. Atual: ${this.simbolos[this.atual].tipo}.`
+                );
+            default:
+                throw this.erro(
+                    this.simbolos[this.atual],
+                    `Símbolo ${this.simbolos[this.atual].tipo} inesperado ou inválido como chave de dicionário.`
+                );
+        }
+    }
+
+    protected construtoDicionario(simboloChaveEsquerda: SimboloInterface): Dicionario {
+        this.avancarEDevolverAnterior();
+        const chaves = [];
+        const valores = [];
+
+        if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CHAVE_DIREITA)) {
+            return new Dicionario(this.hashArquivo, Number(simboloChaveEsquerda.linha), [], []);
+        }
+
+        while (!this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CHAVE_DIREITA)) {
+            const chave = this.obterChaveDicionario();
+            this.consumir(tiposDeSimbolos.DOIS_PONTOS, "Esperado ':' entre chave e valor.");
+            const valor = this.atribuir();
+
+            chaves.push(chave);
+            valores.push(valor);
+
+            if (this.simbolos[this.atual].tipo !== tiposDeSimbolos.CHAVE_DIREITA) {
+                this.consumir(tiposDeSimbolos.VIRGULA, 'Esperado vírgula antes da próxima expressão.');
+            }
+        }
+
+        return new Dicionario(this.hashArquivo, Number(simboloChaveEsquerda.linha), chaves, valores);
+    }
+
+    protected construtoTupla(): Tupla {
+        const expressao = this.expressao();
+        const argumentos = [expressao];
+        while (this.simbolos[this.atual].tipo === tiposDeSimbolos.VIRGULA) {
+            this.avancarEDevolverAnterior();
+            argumentos.push(this.expressao());
+        }
+
+        this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
+        this.consumir(tiposDeSimbolos.COLCHETE_DIREITO, "Esperado ']' após a expressão.");
+        return new SeletorTuplas(...argumentos) as Tupla;
+    }
+
+    override primario(): Construto {
+        const simboloAtual = this.simbolos[this.atual];
+        let valores = [];
+        switch (simboloAtual.tipo) {
+            case tiposDeSimbolos.CHAVE_ESQUERDA:
+                return this.construtoDicionario(simboloAtual);
+
+            case tiposDeSimbolos.COLCHETE_ESQUERDO:
+                this.avancarEDevolverAnterior();
+                valores = [];
+
+                if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_DIREITO)) {
+                    return new Vetor(this.hashArquivo, Number(simboloAtual.linha), [], 0, 'qualquer[]');
+                }
+
+                while (!this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_DIREITO)) {
+                    if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO)) {
+                        return this.construtoTupla();
+                    }
+
+                    const valor = this.atribuir();
+                    valores.push(valor);
+                    if (this.simbolos[this.atual].tipo !== tiposDeSimbolos.COLCHETE_DIREITO) {
+                        this.consumir(tiposDeSimbolos.VIRGULA, 'Esperado vírgula antes da próxima expressão.');
+                    }
+                }
+
+                const tipoVetor = inferirTipoVariavel(valores);
+                return new Vetor(this.hashArquivo, Number(simboloAtual.linha), valores, valores.length, tipoVetor);
+
+            case tiposDeSimbolos.EXPRESSAO_REGULAR:
+                let valor: string = '';
+                let linhaAtual = this.simbolos[this.atual].linha;
+                let eParExpressaoRegular =
+                    this.simbolos.filter((l) => l.linha === linhaAtual && l.tipo === tiposDeSimbolos.EXPRESSAO_REGULAR)
+                        .length %
+                        2 ===
+                    0;
+                if (eParExpressaoRegular) {
+                    this.avancarEDevolverAnterior();
+                    while (!this.verificarTipoSimboloAtual(tiposDeSimbolos.EXPRESSAO_REGULAR)) {
+                        valor += this.simbolos[this.atual].lexema || '';
+                        this.avancarEDevolverAnterior();
+                    }
+                    this.avancarEDevolverAnterior();
+                    return new ExpressaoRegular(this.hashArquivo, simboloAtual, valor);
+                }
+
+            case tiposDeSimbolos.FALSO:
+                this.avancarEDevolverAnterior();
+                return new Literal(this.hashArquivo, Number(simboloAtual.linha), false, 'lógico');
+
+            case tiposDeSimbolos.FUNCAO:
+            case tiposDeSimbolos.FUNÇÃO:
+                const simboloFuncao = this.avancarEDevolverAnterior();
+                // Avançamos o parêntese esquerdo aqui, porque `corpoDaFuncao`
+                // espera que esse parêntese esquerdo já foi consumido.
+                this.consumir(tiposDeSimbolos.PARENTESE_ESQUERDO, "Esperado parêntese esquerdo após palavra reservada 'função'.");
+                const corpoDaFuncao = this.corpoDaFuncao(simboloFuncao.lexema as any);
+                this.pilhaEscopos.definirInformacoesVariavel(
+                    simboloFuncao.lexema, 
+                    new InformacaoVariavelOuConstante(simboloFuncao.lexema, 'função'));
+                return corpoDaFuncao;
+
+            case tiposDeSimbolos.IDENTIFICADOR:
+                const simboloIdentificador: SimboloInterface = this.avancarEDevolverAnterior();
+                let tipoOperando: string;
+                if (simboloIdentificador.lexema in this.tiposDefinidosEmCodigo) {
+                    tipoOperando = simboloIdentificador.lexema;
+                } else {
+                    tipoOperando = this.pilhaEscopos.obterTipoVariavelPorNome(simboloIdentificador.lexema);
+                }
+
+                // Se o próximo símbolo é um incremento ou um decremento,
+                // aqui deve retornar um unário correspondente.
+                // Caso contrário, apenas retornar um construto de variável.
+                if (
+                    this.simbolos[this.atual] &&
+                    [tiposDeSimbolos.INCREMENTAR, tiposDeSimbolos.DECREMENTAR].includes(this.simbolos[this.atual].tipo)
+                ) {
+                    const simboloIncrementoDecremento: SimboloInterface = this.avancarEDevolverAnterior();
+                    return new Unario(
+                        this.hashArquivo,
+                        simboloIncrementoDecremento,
+                        new Variavel(this.hashArquivo, simboloIdentificador, tipoOperando || 'qualquer'),
+                        'DEPOIS'
+                    );
+                }
+
+                return new Variavel(this.hashArquivo, simboloIdentificador, tipoOperando || 'qualquer');
+
+            case tiposDeSimbolos.LEIA:
+                return this.expressaoLeia();
+
+            case tiposDeSimbolos.NADA:
+                this.avancarEDevolverAnterior();
+                return new Literal(this.hashArquivo, Number(simboloAtual.linha), null, 'nulo');
+
+            case tiposDeSimbolos.NUMERO:
+            case tiposDeSimbolos.NÚMERO:
+            case tiposDeSimbolos.TEXTO:
+                const simboloNumeroTexto: SimboloInterface = this.avancarEDevolverAnterior();
+                const tipoInferido = inferirTipoVariavel(simboloNumeroTexto.literal);
+                const tipoDadosElementar = tipoInferenciaParaTipoDadosElementar(tipoInferido as TipoInferencia);
+                return new Literal(
+                    this.hashArquivo,
+                    Number(simboloNumeroTexto.linha),
+                    simboloNumeroTexto.literal,
+                    tipoDadosElementar
+                );
+
+            case tiposDeSimbolos.PARENTESE_ESQUERDO:
+                this.avancarEDevolverAnterior();
+                const expressao = this.expressao();
+                this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
+
+                return new Agrupamento(this.hashArquivo, Number(simboloAtual.linha), expressao);
+
+            case tiposDeSimbolos.SUPER:
+                const simboloSuper = this.avancarEDevolverAnterior();
+                if (!this.superclasseAtual) {
+                    throw this.erro(
+                        this.simbolos[this.atual],
+                        "'Super' usado fora de declaração de classe com herança."
+                    );
+                }
+
+                return new Super(this.hashArquivo, simboloSuper, this.superclasseAtual);
+
+            case tiposDeSimbolos.VERDADEIRO:
+                this.avancarEDevolverAnterior();
+                return new Literal(this.hashArquivo, Number(simboloAtual.linha), true, 'lógico');
+        }
+
+        throw this.erro(this.simbolos[this.atual], 'Esperado expressão.');
+    }
+
+    override chamar(): Construto {
+        let expressao = this.primario();
+
+        while (true) {
+            let tipoPrimitiva: string = undefined;
+            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO)) {
+                expressao = this.finalizarChamada(expressao, tipoPrimitiva);
+            } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO)) {
+                const nome = this.consumir(
+                    tiposDeSimbolos.IDENTIFICADOR,
+                    "Esperado nome de método ou propriedade após '.'."
+                );
+
+                tipoPrimitiva = expressao.tipo;
+                expressao = new AcessoMetodoOuPropriedade(this.hashArquivo, expressao, nome);
+            } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_ESQUERDO)) {
+                const indice = this.expressao();
+                const simboloFechamento = this.consumir(
+                    tiposDeSimbolos.COLCHETE_DIREITO,
+                    "Esperado ']' após escrita do indice."
+                );
+                expressao = new AcessoIndiceVariavel(this.hashArquivo, expressao, indice, simboloFechamento);
+            } else {
+                break;
+            }
+        }
+
+        return expressao;
+    }
+
+    /**
+     * `AcessoMetodoOuPropriedade` é um construto intermediário em Delégua, e deve ser resolvido como outro
+     * construto antes de qualquer outra próxima etapa. Algumas validações adicionais também ocorrem aqui.
+     * @param {AcessoMetodoOuPropriedade} entidadeChamadaResolvida O construto original.
+     * @returns {Construto} O construto resolvido como um tipo mais específico.
+     * @see finalizarChamada
+     */
+    protected resolverEntidadeChamadaAcessoMetodoOuPropriedade(
+        entidadeChamadaResolvida: AcessoMetodoOuPropriedade
+    ): Construto {
+        const construtoTipado: AcessoMetodoOuPropriedade = entidadeChamadaResolvida;
+        switch (entidadeChamadaResolvida.tipo) {
+            case tipoDeDadosDelegua.DICIONARIO:
+            case tipoDeDadosDelegua.DICIONÁRIO:
+                if (!(construtoTipado.simbolo.lexema in primitivasDicionario)) {
+                    throw this.erro(
+                        construtoTipado.simbolo,
+                        `${construtoTipado.simbolo.lexema} não é uma primitiva de dicionário.`
+                    );
+                }
+
+                const primitivaDicionarioSelecionada = primitivasDicionario[construtoTipado.simbolo.lexema];
+                return new AcessoMetodo(
+                    construtoTipado.hashArquivo,
+                    construtoTipado.objeto,
+                    construtoTipado.simbolo.lexema,
+                    primitivaDicionarioSelecionada.tipoRetorno
+                );
+
+            case tipoDeDadosDelegua.INTEIRO:
+            case tipoDeDadosDelegua.NUMERO:
+            case tipoDeDadosDelegua.NÚMERO:
+                if (!(construtoTipado.simbolo.lexema in primitivasNumero)) {
+                    throw this.erro(
+                        construtoTipado.simbolo,
+                        `${construtoTipado.simbolo.lexema} não é uma primitiva de número.`
+                    );
+                }
+
+                const primitivaNumeroSelecionada = primitivasNumero[construtoTipado.simbolo.lexema];
+                return new AcessoMetodo(
+                    construtoTipado.hashArquivo,
+                    construtoTipado.objeto,
+                    construtoTipado.simbolo.lexema,
+                    primitivaNumeroSelecionada.tipoRetorno
+                );
+
+            case tipoDeDadosDelegua.MODULO:
+            case tipoDeDadosDelegua.MÓDULO:
+                if (construtoTipado.simbolo.lexema in this.tiposDefinidosEmCodigo) {
+                    // Construtor de classe.
+                    return new Variavel(
+                        construtoTipado.hashArquivo,
+                        construtoTipado.simbolo,
+                        construtoTipado.objeto.tipo
+                    );
+                }
+
+                return new AcessoMetodo(
+                    construtoTipado.hashArquivo,
+                    construtoTipado.objeto,
+                    construtoTipado.simbolo.lexema
+                );
+
+            case tipoDeDadosDelegua.TEXTO:
+                if (!(construtoTipado.simbolo.lexema in primitivasTexto)) {
+                    throw this.erro(
+                        construtoTipado.simbolo,
+                        `${construtoTipado.simbolo.lexema} não é uma primitiva de texto.`
+                    );
+                }
+
+                const primitivaTextoSelecionada = primitivasTexto[construtoTipado.simbolo.lexema];
+                return new AcessoMetodo(
+                    construtoTipado.hashArquivo,
+                    construtoTipado.objeto,
+                    construtoTipado.simbolo.lexema,
+                    primitivaTextoSelecionada.tipoRetorno
+                );
+            case tipoDeDadosDelegua.VETOR:
+            case tipoDeDadosDelegua.VETOR_NUMERO:
+            case tipoDeDadosDelegua.VETOR_NÚMERO:
+            case tipoDeDadosDelegua.VETOR_TEXTO:
+                if (!(construtoTipado.simbolo.lexema in primitivasVetor)) {
+                    throw this.erro(
+                        construtoTipado.simbolo,
+                        `${construtoTipado.simbolo.lexema} não é uma primitiva de vetor.`
+                    );
+                }
+
+                const primitivaVetorSelecionada = primitivasVetor[construtoTipado.simbolo.lexema];
+                return new AcessoMetodo(
+                    construtoTipado.hashArquivo,
+                    construtoTipado.objeto,
+                    construtoTipado.simbolo.lexema,
+                    primitivaVetorSelecionada.tipoRetorno
+                );
+        }
+
+        return entidadeChamadaResolvida;
+    }
+
+    protected validarArgumentosEntidadeChamada(
+        argumentosEntidadeChamada: InformacaoVariavelOuConstante[], 
+        argumentosUtilizados: Construto[]
+    ): string[] {
+        if (argumentosEntidadeChamada.length === 0) {
+            return [];
+        }
+
+        const possiveisErros = [];
+        for (const [indice, argumentoEntidadeChamada] of argumentosEntidadeChamada.entries()) {
+            const argumentoUtilizado = argumentosUtilizados[indice];
+            if (argumentoUtilizado.tipo === null || argumentoUtilizado.tipo === undefined) {
+                continue;
+            }
+
+            const argumentoEntidadeChamadaVetor = argumentoEntidadeChamada.tipo.endsWith('[]');
+            const argumentoUtilizadoVetor = argumentoUtilizado.tipo.endsWith('[]');
+
+            if (argumentoEntidadeChamadaVetor !== argumentoUtilizadoVetor) {
+                possiveisErros.push(`Argumento: ${argumentoEntidadeChamada.nome}. Tipo esperado: ${argumentoEntidadeChamada.tipo}; Tipo utilizado: ${argumentoUtilizado.tipo}`);
+                continue;
+            }
+
+            const argumentoEntidadeChamadaQualquer = argumentoEntidadeChamada.tipo.startsWith('qualquer');
+            if (argumentoEntidadeChamadaQualquer) {
+                continue;
+            }
+
+            if (argumentoUtilizado.tipo !== argumentoEntidadeChamada.tipo) {
+                possiveisErros.push(`Argumento: ${argumentoEntidadeChamada.nome}. Tipo esperado: ${argumentoEntidadeChamada.tipo}; Tipo utilizado: ${argumentoUtilizado.tipo}`);
+            }
+        }
+        
+        return possiveisErros;
+    }
+
+    /**
+     * Diversas verificações de resolução de entidade chamada, como resolver chamada da pilha ou usar referência, argumentos, etc.
+     * @param entidadeChamada O construto da entidade chamada.
+     * @param argumentos Os argumentos utilizados na chamada.
+     * @param tipoPrimitiva Se for uma primitiva, o tipo dela. Senão, `undefined`.
+     * @returns A entidade chamada resolvida, se as validações passarem.
+     */
+    protected resolverEntidadeChamada(entidadeChamada: Construto, argumentos: Construto[], tipoPrimitiva: string | undefined = undefined): Construto {
+        if (entidadeChamada.constructor.name === 'Variavel') {
+            const entidadeChamadaResolvidaVariavel = entidadeChamada as Variavel;
+
+            if (tipoPrimitiva === undefined) {
+                // Provavelmente uma chamada a alguma função da biblioteca global.
+                const informacoesPossivelFuncaoBibliotecaGlobal = this.pilhaEscopos.obterBibliotecaGlobal(entidadeChamadaResolvidaVariavel.simbolo.lexema);
+                if (informacoesPossivelFuncaoBibliotecaGlobal !== undefined) {
+                    const erros = this.validarArgumentosEntidadeChamada(informacoesPossivelFuncaoBibliotecaGlobal.argumentos, argumentos);
+                    if (erros.length > 0) {
+                        throw new ErroAvaliadorSintatico(
+                            entidadeChamadaResolvidaVariavel.simbolo, 
+                            `Erros ao resolver argumentos de chamada a ${entidadeChamadaResolvidaVariavel.simbolo.lexema}: \n${erros.reduce((mensagem, erro) => mensagem += `${erro}\n`, '')}`
+                        );
+                    }
+
+                    return entidadeChamadaResolvidaVariavel;
+                }
+            }
+
+            if (tipoPrimitiva !== undefined && this.primitivasConhecidas.hasOwnProperty(entidadeChamadaResolvidaVariavel.simbolo.lexema)) {
+                var informacoesPrimitiva = this.primitivasConhecidas[entidadeChamadaResolvidaVariavel.simbolo.lexema];
+                const erros = this.validarArgumentosEntidadeChamada(informacoesPrimitiva.argumentos, argumentos);
+                if (erros.length > 0) {
+                    throw new ErroAvaliadorSintatico(
+                        entidadeChamadaResolvidaVariavel.simbolo, 
+                        `Erros ao resolver argumentos de chamada a ${entidadeChamadaResolvidaVariavel.simbolo.lexema}: \n${erros.reduce((mensagem, erro) => mensagem += `${erro}\n`, '')}`
+                    );
+                }
+
+                return entidadeChamadaResolvidaVariavel;
+            }
+
+            if (entidadeChamadaResolvidaVariavel.simbolo.lexema in this.tiposDefinidosEmCodigo) {
+                return entidadeChamadaResolvidaVariavel;
+            }
+
+            const possivelReferencia = this.pilhaEscopos.obterReferenciaFuncao(
+                entidadeChamadaResolvidaVariavel.simbolo.lexema
+            );
+
+            if (possivelReferencia !== null) {
+                return new ReferenciaFuncao(
+                    entidadeChamada.hashArquivo,
+                    entidadeChamada.linha,
+                    entidadeChamadaResolvidaVariavel.simbolo,
+                    entidadeChamadaResolvidaVariavel.tipo,
+                    possivelReferencia.id
+                );
+            }
+
+            return new ArgumentoReferenciaFuncao(
+                entidadeChamada.hashArquivo,
+                entidadeChamada.linha,
+                entidadeChamadaResolvidaVariavel.simbolo
+            );
+        }
+
+        if (entidadeChamada.constructor.name === 'AcessoMetodoOuPropriedade') {
+            return this.resolverEntidadeChamadaAcessoMetodoOuPropriedade(entidadeChamada as AcessoMetodoOuPropriedade);
+        }
+
+        return entidadeChamada;
+    }
+
+    protected declaracaoDeFuncao(identificador: SimboloInterface<string>): FuncaoDeclaracao {
+        // Se houver chamadas recursivas à função, precisamos definir um tipo
+        // para ela. Vai ser atualizado após avaliação do corpo da função.
+        this.pilhaEscopos.definirInformacoesVariavel(
+            identificador.lexema, 
+            new InformacaoVariavelOuConstante(identificador.lexema, 'qualquer')
+        );
+
+        const corpoDaFuncao = this.corpoDaFuncao('implícita');
+        this.pilhaEscopos.definirInformacoesVariavel(
+            identificador.lexema, 
+            new InformacaoVariavelOuConstante(identificador.lexema, corpoDaFuncao.tipo)
+        );
+        const funcaoDeclaracao = new FuncaoDeclaracao(identificador, corpoDaFuncao, corpoDaFuncao.tipo);
+        this.pilhaEscopos.registrarReferenciaFuncao(identificador.lexema, funcaoDeclaracao);
+        return funcaoDeclaracao;
+    }
+
+    override finalizarChamada(entidadeChamada: Construto, tipoPrimitiva: string | undefined = undefined): Chamada {
+        const argumentos: Array<Construto> = [];
+
+        if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PARENTESE_DIREITO)) {
+            do {
+                // `apply()` em JavaScript aceita até 255 parâmetros.
+                if (argumentos.length >= 255) {
+                    throw this.erro(this.simbolos[this.atual], 'Não pode haver mais de 255 argumentos.');
+                }
+                argumentos.push(this.expressao());
+            } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
+        }
+
+        this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após os argumentos.");
+
+        // Toda chamada precisa saber de antemão qual o tipo resolvido.
+        const entidadeChamadaResolvida = this.resolverEntidadeChamada(entidadeChamada, argumentos, tipoPrimitiva);
+
+        // TODO: Criar forma de validar tipos dos argumentos da entidade chamada.
+        const construtoChamada = new Chamada(this.hashArquivo, entidadeChamadaResolvida, argumentos);
+        construtoChamada.tipo = 'qualquer';
+        return construtoChamada;
+    }
+
+    override unario(): Construto {
+        if (
+            this.verificarSeSimboloAtualEIgualA(
+                tiposDeSimbolos.NÃO,
+                tiposDeSimbolos.SUBTRACAO,
+                tiposDeSimbolos.BIT_NOT,
+                tiposDeSimbolos.INCREMENTAR,
+                tiposDeSimbolos.DECREMENTAR
+            )
+        ) {
+            const operador = this.simbolos[this.atual - 1];
+            const direito = this.unario();
+            return new Unario(this.hashArquivo, operador, direito, 'ANTES');
+        }
+
+        return this.chamar();
+    }
+
+    override multiplicar(): Construto {
+        let expressao = this.exponenciacao();
+
+        while (
+            this.verificarSeSimboloAtualEIgualA(
+                tiposDeSimbolos.DIVISAO,
+                tiposDeSimbolos.DIVISAO_IGUAL,
+                tiposDeSimbolos.DIVISAO_INTEIRA,
+                tiposDeSimbolos.DIVISAO_INTEIRA_IGUAL,
+                tiposDeSimbolos.MODULO,
+                tiposDeSimbolos.MODULO_IGUAL,
+                tiposDeSimbolos.MULTIPLICACAO,
+                tiposDeSimbolos.MULTIPLICACAO_IGUAL
+            )
+        ) {
+            const operador = this.simbolos[this.atual - 1];
+            const direito = this.exponenciacao();
+            expressao = new Binario<TipoDeSimboloDelegua>(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    /**
+     * Se símbolo de operação é `+`, `-`, `+=` ou `-=`, monta objeto `Binario` para
+     * ser avaliado pelo Interpretador.
+     * @returns Um Construto, normalmente um `Binario`, ou `Unario` se houver alguma operação unária para ser avaliada.
+     */
+    override adicaoOuSubtracao(): Construto {
+        let expressao = this.multiplicar();
+
+        while (
+            this.verificarSeSimboloAtualEIgualA(
+                tiposDeSimbolos.SUBTRACAO,
+                tiposDeSimbolos.ADICAO,
+                tiposDeSimbolos.MENOS_IGUAL
+            )
+        ) {
+            const operador = this.simbolos[this.atual - 1];
+
+            const direito = this.multiplicar();
+            // const tipoInferido = inferirTipoParaBinario(expressao, operador, direito);
+            expressao = new Binario<TipoDeSimboloDelegua>(this.hashArquivo, expressao, operador, direito);
+        }
+
+        if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.MAIS_IGUAL)) {
+            const operador = this.simbolos[this.atual - 1];
+
+            const direito = this.atribuir();
+            expressao = new Binario<TipoDeSimboloDelegua>(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    override bitShift(): Construto {
+        let expressao = this.adicaoOuSubtracao();
+
+        while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.MENOR_MENOR, tiposDeSimbolos.MAIOR_MAIOR)) {
+            const operador = this.simbolos[this.atual - 1];
+            const direito = this.adicaoOuSubtracao();
+            expressao = new Binario<TipoDeSimboloDelegua>(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    override bitE(): Construto {
+        let expressao = this.bitShift();
+
+        while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.BIT_AND)) {
+            const operador = this.simbolos[this.atual - 1];
+            const direito = this.bitShift();
+            expressao = new Binario<TipoDeSimboloDelegua>(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    override bitOu(): Construto {
+        let expressao = this.bitE();
+
+        while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.BIT_OR, tiposDeSimbolos.BIT_XOR)) {
+            const operador = this.simbolos[this.atual - 1];
+            const direito = this.bitE();
+            expressao = new Binario<TipoDeSimboloDelegua>(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    override comparar(): Construto {
+        let expressao = this.bitOu();
+
+        while (
+            this.verificarSeSimboloAtualEIgualA(
+                tiposDeSimbolos.MAIOR,
+                tiposDeSimbolos.MAIOR_IGUAL,
+                tiposDeSimbolos.MENOR,
+                tiposDeSimbolos.MENOR_IGUAL
+            )
+        ) {
+            const operador = this.simbolos[this.atual - 1];
+            const direito = this.bitOu();
+            expressao = new Binario<TipoDeSimboloDelegua>(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    override comparacaoIgualdade(): Construto {
+        let expressao = this.comparar();
+
+        while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.NÃO, tiposDeSimbolos.É)) {
+            const operador = this.simbolos[this.atual - 1];
+            if (operador.tipo === tiposDeSimbolos.NÃO) {
+                this.consumir(tiposDeSimbolos.É, `Esperado 'é' após 'não'.`);
+                operador.tipo = tiposDeSimbolos.DIFERENTE;
+                operador.lexema = "não é";
+                operador.literal = "não é";
+            }
+
+            const direito = this.comparar();
+            expressao = new Binario<TipoDeSimboloDelegua>(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    override em(): Construto {
+        let expressao = this.comparacaoIgualdade();
+
+        while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.TEM)) {
+            const operador = this.simbolos[this.atual - 1];
+            const direito = this.comparacaoIgualdade();
+            expressao = new Logico(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    override e(): Construto {
+        let expressao = this.em();
+
+        while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.E)) {
+            const operador = this.simbolos[this.atual - 1];
+            const direito = this.em();
+            expressao = new Logico(this.hashArquivo, expressao, operador, direito);
+        }
+
+        return expressao;
+    }
+
+    /**
+     * Método que resolve atribuições.
+     * @returns Um construto do tipo `Atribuir`, `Conjunto` ou `AtribuicaoPorIndice`.
+     */
+    override atribuir(): Construto {
+        const expressao = this.ou();
+
+        if (
+            expressao instanceof Binario &&
+            [
+                tiposDeSimbolos.MAIS_IGUAL,
+                tiposDeSimbolos.MENOS_IGUAL,
+                tiposDeSimbolos.MULTIPLICACAO_IGUAL,
+                tiposDeSimbolos.DIVISAO_IGUAL,
+                tiposDeSimbolos.DIVISAO_INTEIRA_IGUAL,
+                tiposDeSimbolos.MODULO_IGUAL,
+            ].includes(expressao.operador.tipo)
+        ) {
+            if (expressao.esquerda instanceof AcessoIndiceVariavel) {
+                const entidade = expressao.esquerda as AcessoIndiceVariavel;
+                return new Atribuir(
+                    this.hashArquivo,
+                    entidade.entidadeChamada,
+                    expressao,
+                    entidade.indice,
+                    expressao.operador
+                );
+            }
+
+            return new Atribuir(this.hashArquivo, expressao.esquerda, expressao, undefined, expressao.operador);
+        } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) {
+            const igual = this.simbolos[this.atual - 1];
+            const valor = this.expressao();
+
+            switch (expressao.constructor.name) {
+                case 'Variavel':
+                    return new Atribuir(this.hashArquivo, expressao, valor);
+                case 'AcessoMetodoOuPropriedade':
+                    const expressaoAcessoMetodoOuPropriedade = expressao as AcessoMetodoOuPropriedade;
+                    return new DefinirValor(
+                        this.hashArquivo,
+                        igual.linha,
+                        expressaoAcessoMetodoOuPropriedade.objeto,
+                        expressaoAcessoMetodoOuPropriedade.simbolo,
+                        valor
+                    );
+                case 'AcessoIndiceVariavel':
+                    const expressaoAcessoIndiceVariavel = expressao as AcessoIndiceVariavel;
+                    return new AtribuicaoPorIndice(
+                        this.hashArquivo,
+                        expressaoAcessoIndiceVariavel.linha,
+                        expressaoAcessoIndiceVariavel.entidadeChamada,
+                        expressaoAcessoIndiceVariavel.indice,
+                        valor
+                    );
+            }
+
+            throw this.erro(igual, 'Tarefa de atribuição inválida');
+        }
+
+        return expressao;
+    }
+
+    /**
+     * Declaração para comando `leia`, para ler dados de entrada do usuário.
+     * @returns Um objeto da classe `Leia`.
+     */
+    override expressaoLeia(): Leia {
+        const simboloLeia = this.avancarEDevolverAnterior();
+
+        this.consumir(tiposDeSimbolos.PARENTESE_ESQUERDO, "Esperado '(' antes dos argumentos em instrução `leia`.");
+
+        const argumentos: Construto[] = [];
+
+        if (this.simbolos[this.atual].tipo !== tiposDeSimbolos.PARENTESE_DIREITO) {
+            do {
+                argumentos.push(this.expressao());
+            } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
+        }
+
+        this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após os argumentos em instrução `leia`.");
+
+        return new Leia(simboloLeia, argumentos);
+    }
+
+    // TODO: Depreciar.
+    override expressao(): Construto {
+        return this.atribuir();
+    }
+
+    override blocoEscopo(tipo?: string): Array<Declaracao> {
+        this.pilhaEscopos.empilhar(new InformacaoEscopo());
+        let declaracoes: Array<Declaracao> = [];
+
+        while (!this.verificarTipoSimboloAtual(tiposDeSimbolos.FIM) && !this.estaNoFinal()) {
+            const retornoDeclaracao = this.resolverDeclaracaoForaDeBloco();
+            if (Array.isArray(retornoDeclaracao)) {
+                declaracoes = declaracoes.concat(retornoDeclaracao);
+            } else {
+                declaracoes.push(retornoDeclaracao as Declaracao);
+            }
+        }
+
+        this.consumir(tiposDeSimbolos.FIM, `Esperado 'fim' para concluir bloco de escopo ${tipo ? "de " + tipo : ''}.`);
+        this.pilhaEscopos.removerUltimo();
+
+        return declaracoes;
+    }
+
+    protected declaracaoComentarioUmaLinha(): Comentario {
+        const simboloComentario = this.avancarEDevolverAnterior();
+        return new Comentario(simboloComentario.hashArquivo, simboloComentario.linha, simboloComentario.literal, false);
+    }
+
+    override declaracaoContinua(): Continua {
+        if (this.blocos < 1) {
+            throw this.erro(this.simbolos[this.atual - 1], "'continua' precisa estar em um laço de repetição.");
+        }
+
+        // Ponto-e-vírgula é opcional aqui.
+        this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
+        return new Continua(this.simbolos[this.atual - 1]);
+    }
+
+    override declaracaoEnquanto(): Enquanto {
+        try {
+            const simboloEnquanto = this.simbolos[this.atual - 1];
+            this.blocos += 1;
+
+            const condicao = this.expressao();
+
+            this.consumir(tiposDeSimbolos.FAÇA, "Esperado 'faça' depois da condição.")
+
+            const blocoCorpo = this.blocoEscopo('enquanto');
+
+            return new Enquanto(condicao, new Bloco(simboloEnquanto.linha, simboloEnquanto.hashArquivo, blocoCorpo));
+        } finally {
+            this.blocos -= 1;
+        }
+    }
+
+    override declaracaoEscreva(): Escreva {
+        const simboloAtual = this.simbolos[this.atual];
+
+        this.consumir(tiposDeSimbolos.PARENTESE_ESQUERDO, "Esperado '(' antes dos valores em escreva.");
+
+        const argumentos: Construto[] = [];
+
+        if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PARENTESE_DIREITO)) {
+            do {
+                argumentos.push(this.expressao());
+            } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
+        }
+
+        this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após os valores em escreva.");
+
+        // Ponto-e-vírgula é opcional aqui.
+        // this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
+
+        return new Escreva(Number(simboloAtual.linha), simboloAtual.hashArquivo, argumentos);
+    }
+
+    protected declaracaoExpressao(): Expressao {
+        const expressao = this.expressao();
+        // Ponto-e-vírgula é opcional aqui.
+        this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
+        return new Expressao(expressao);
+    }
+
+    override declaracaoPara(): Para | ParaCada {
+        const simboloPara: SimboloInterface = this.simbolos[this.atual - 1];
+        this.consumir(tiposDeSimbolos.CADA, `Esperado palavra reservada 'cada' após 'para'.`);
+        this.blocos += 1;
+
+        const nomeVariavelIteracao = this.consumir(
+            tiposDeSimbolos.IDENTIFICADOR,
+            "Esperado identificador de variável de iteração para instrução 'para cada'."
+        );
+
+        this.consumir(tiposDeSimbolos.EM, "Esperado palavra reservada 'em' após variável de iteração em instrução 'para cada'.");
+
+        // Se for um literal ou identificador numérico, segue um `para` 
+        // tradicional de Delégua, com variável de controle e passo positivo, incrementado em 1.
+        const literalOuVariavelInicio = this.adicaoOuSubtracao();
+        this.blocos -= 1;
+        switch (literalOuVariavelInicio.constructor.name) {
+            case 'Literal':
+                return this.declaracaoParaTradicional(simboloPara, nomeVariavelIteracao, literalOuVariavelInicio);
+            // TODO: Terminar
+            case 'Variavel':
+            case 'Vetor':
+            default:
+                return this.declaracaoParaCada(simboloPara, nomeVariavelIteracao, literalOuVariavelInicio);
+        }
+    }
+
+    protected declaracaoParaCada(
+        simboloParaCada: SimboloInterface,
+        simboloVariavelIteracao: SimboloInterface,
+        literalOuVariavelIteravel: Construto
+    ): ParaCada {
+        const tipoVetor = (literalOuVariavelIteravel as any).tipo as string;
+        // TODO: Permitir 'qualquer' aqui é bastante frágil. Criar uma forma de validar o tipo
+        // antes dessa avaliação.
+        if (!tipoVetor.endsWith('[]') && !['qualquer', 'vetor'].includes(tipoVetor)) {
+            throw this.erro(
+                simboloParaCada,
+                `Variável ou constante em 'para cada' não é iterável. Tipo resolvido: ${tipoVetor}.`
+            );
+        }
+
+        let tipoVariavelIteracao = 'qualquer';
+        if (tipoVetor.endsWith('[]')) {
+            tipoVariavelIteracao = tipoVetor.slice(0, -2);
+        }
+
+        this.pilhaEscopos.definirInformacoesVariavel(
+            simboloVariavelIteracao.lexema, 
+            new InformacaoVariavelOuConstante(simboloVariavelIteracao.lexema, tipoVariavelIteracao)
+        );
+
+        this.consumir(tiposDeSimbolos.FAÇA, "Esperado palavra reservada 'faça' após literal ou variável de iteração em declaração 'para cada'.");
+
+        const corpo: Array<Declaracao> = this.blocoEscopo();
+
+        return new ParaCada(
+            this.hashArquivo, 
+            Number(simboloParaCada.linha), 
+            simboloVariavelIteracao.lexema, 
+            literalOuVariavelIteravel, 
+            new Bloco(simboloParaCada.hashArquivo, simboloParaCada.linha, corpo)
+        );
+    }
+
+    protected declaracaoParaTradicional(
+        simboloPara: SimboloInterface, 
+        simboloVariavelIteracao: SimboloInterface,
+        literalOuVariavelInicio: Construto
+    ): Para {
+        this.consumir(tiposDeSimbolos.ATÉ, "Esperado palavra reservada 'até' após literal ou identificador de início de declaração 'para cada'.");
+
+        const literalOuVariavelFim = this.adicaoOuSubtracao();
+
+        this.consumir(tiposDeSimbolos.FAÇA, "Esperado palavra reservada 'faça' após literal ou variável de passo final em declaração 'para cada'.");
+
+        // A variável de iteração precisa ser definida aqui, para que o corpo de `para cada` (um escopo)
+        // seja capaz de reconhecer a variável e seu tipo.
+        this.pilhaEscopos.definirInformacoesVariavel(
+            simboloVariavelIteracao.lexema, 
+            new InformacaoVariavelOuConstante(simboloVariavelIteracao.lexema, 'inteiro')
+        );
+
+        const corpo: Array<Declaracao> = this.blocoEscopo();
+
+        // `variavelIteracao <= valorFinal`
+        let operadorCondicao = new Simbolo(
+            tiposDeSimbolos.MENOR_IGUAL,
+            '<=',
+            null,
+            Number(simboloPara.linha),
+            this.hashArquivo
+        );
+        let operadorCondicaoIncremento = new Simbolo(
+            tiposDeSimbolos.MENOR,
+            '<',
+            null,
+            Number(simboloPara.linha),
+            this.hashArquivo
+        );
+
+        return new Para(
+            this.hashArquivo, 
+            Number(simboloPara.linha), 
+            // Inicialização.
+            new Expressao(
+                new Atribuir(
+                    this.hashArquivo,
+                    new Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'),
+                    literalOuVariavelInicio
+                )
+            ),
+            // Condição.
+            new Binario(
+                this.hashArquivo,
+                new Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'),
+                operadorCondicao,
+                literalOuVariavelFim
+            ),
+            // Incremento, feito em construto especial `FimPara`.
+            new FimPara(
+                this.hashArquivo,
+                Number(simboloPara.linha),
+                new Binario(
+                    this.hashArquivo,
+                    new Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'),
+                    operadorCondicaoIncremento,
+                    literalOuVariavelFim
+                ),
+                new Expressao(
+                    new Atribuir(
+                        this.hashArquivo,
+                        new Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'),
+                        new Binario(
+                            this.hashArquivo,
+                            new Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'),
+                            new Simbolo(tiposDeSimbolos.ADICAO, '+', null, Number(simboloPara.linha), this.hashArquivo),
+                            new Literal(this.hashArquivo, Number(simboloPara.linha), 1)
+                        )
+                    )
+                )
+            ),
+            new Bloco(simboloPara.hashArquivo, simboloPara.linha, corpo)
+        );
+    }
+
+    override declaracaoRetorna(): Retorna {
+        const simboloChave = this.simbolos[this.atual - 1];
+        let valor = null;
+
+        if (
+            [
+                tiposDeSimbolos.CHAVE_ESQUERDA,
+                tiposDeSimbolos.COLCHETE_ESQUERDO,
+                tiposDeSimbolos.FALSO,
+                tiposDeSimbolos.FUNCAO,
+                tiposDeSimbolos.FUNÇÃO,
+                tiposDeSimbolos.IDENTIFICADOR,
+                tiposDeSimbolos.ISTO,
+                tiposDeSimbolos.NÃO,
+                tiposDeSimbolos.NUMERO,
+                tiposDeSimbolos.NADA,
+                tiposDeSimbolos.PARENTESE_ESQUERDO,
+                tiposDeSimbolos.SUPER,
+                tiposDeSimbolos.TEXTO,
+                tiposDeSimbolos.VERDADEIRO,
+            ].includes(this.simbolos[this.atual].tipo)
+        ) {
+            valor = this.expressao();
+        }
+
+        // Ponto-e-vírgula é opcional aqui.
+        this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
+        return new Retorna(simboloChave, valor);
+    }
+
+    override declaracaoSe(): Se {
+        const condicao = this.expressao();
+
+        this.consumir(tiposDeSimbolos.ENTÃO, "Esperado 'então' após a condição.");
+
+        const caminhoEntao: Declaracao = this.resolverDeclaracao() as Declaracao;
+
+        let caminhoSenao = null;
+        if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.SENÃO)) {
+            caminhoSenao = this.resolverDeclaracao();
+        }
+
+        return new Se(condicao, caminhoEntao, [], caminhoSenao);
+    }
+
+    override declaracaoSustar(): Sustar {
+        if (this.blocos < 1) {
+            throw this.erro(
+                this.simbolos[this.atual - 1],
+                "'sustar' ou 'pausa' deve estar dentro de um laço de repetição."
+            );
+        }
+
+        // Ponto-e-vírgula é opcional aqui.
+        this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
+        return new Sustar(this.simbolos[this.atual - 1]);
+    }
+
+    /**
+     * Todas as resoluções triviais da linguagem, ou seja, todas as
+     * resoluções que podem ocorrer dentro ou fora de um bloco.
+     * @returns Normalmente uma `Declaracao`, mas há casos em que
+     * outros objetos podem ser retornados.
+     * @see resolverDeclaracaoForaDeBloco para as declarações que não podem
+     * ocorrer em blocos de escopo elementares.
+     */
+    protected resolverDeclaracao(): Declaracao | Declaracao[] {
+        switch (this.simbolos[this.atual].tipo) {
+            case tiposDeSimbolos.COMENTARIO:
+                return this.declaracaoComentarioUmaLinha();
+            case tiposDeSimbolos.CONTINUA:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoContinua();
+            case tiposDeSimbolos.ENQUANTO:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoEnquanto();
+            case tiposDeSimbolos.EXIBA:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoEscreva();
+            case tiposDeSimbolos.FAÇA:
+                this.avancarEDevolverAnterior();
+                return this.blocoEscopo();
+            case tiposDeSimbolos.PARA:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoPara();
+            case tiposDeSimbolos.PAUSA:
+            case tiposDeSimbolos.SUSTAR:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoSustar();
+            case tiposDeSimbolos.SE:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoSe();
+            case tiposDeSimbolos.RETORNA:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoRetorna();
+            case tiposDeSimbolos.TENTE:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoTente();
+            case tiposDeSimbolos.SEJA:
+                this.avancarEDevolverAnterior();
+                return this.declaracaoDeVariaveisOuFuncoes();
+        }
+
+        const simboloAtual = this.simbolos[this.atual];
+        if (simboloAtual.tipo === tiposDeSimbolos.IDENTIFICADOR) {
+            // Pela gramática, a seguinte situação não pode ocorrer:
+            // 1. O símbolo anterior ser um identificador; e
+            // 2. O símbolo anterior estar na mesma linha do identificador atual.
+
+            const simboloAnterior = this.simbolos[this.atual - 1];
+            if (
+                !!simboloAnterior &&
+                simboloAnterior.tipo === tiposDeSimbolos.IDENTIFICADOR &&
+                simboloAnterior.linha === simboloAtual.linha
+            ) {
+                throw this.erro(
+                    this.simbolos[this.atual],
+                    'Não é permitido ter dois identificadores seguidos na mesma linha.'
+                );
+            }
+        }
+
+        return this.declaracaoExpressao();
+    }
+
+    protected logicaComumInferenciaTiposVariaveis(inicializador: Construto): string {
+        switch (inicializador.constructor.name) {
+            case 'AcessoIndiceVariavel':
+                const entidadeChamadaAcessoIndiceVariavel = (inicializador as AcessoIndiceVariavel).entidadeChamada;
+                return entidadeChamadaAcessoIndiceVariavel.tipo.slice(0, -2);
+            case 'Chamada':
+                const entidadeChamadaChamada = (inicializador as Chamada).entidadeChamada;
+                switch (entidadeChamadaChamada.constructor.name) {
+                    case 'AcessoMetodo':
+                        const entidadeChamadaAcessoMetodo = entidadeChamadaChamada as AcessoMetodo;
+                        return entidadeChamadaAcessoMetodo.tipoRetornoMetodo;
+                    case 'AcessoMetodoOuPropriedade':
+                        // Este caso ocorre quando a variável/constante é do tipo 'qualquer', 
+                        // e a chamada normalmente é feita para uma primitiva. 
+                        // A inferência, portanto, ocorre pelo uso da primitiva.
+                        const entidadeChamadaAcessoMetodoOuPropriedade = entidadeChamadaChamada as AcessoMetodoOuPropriedade;
+                        if (this.primitivasConhecidas.hasOwnProperty(entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema)) {
+                            return this.primitivasConhecidas[entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema].tipo;
+                        }
+
+                        throw new ErroAvaliadorSintatico(
+                            entidadeChamadaAcessoMetodoOuPropriedade.simbolo, 
+                            `Primitiva '${entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema}' não existe.`
+                        );
+                    case 'AcessoPropriedade':
+                        const entidadeChamadaAcessoPropriedade = entidadeChamadaChamada as AcessoPropriedade;
+                        return entidadeChamadaAcessoPropriedade.tipoRetornoPropriedade;
+                    case 'ArgumentoReferenciaFuncao':
+                        // TODO: Voltar aqui se necessário.
+                        return 'qualquer';
+                    case 'ReferenciaFuncao':
+                        const entidadeChamadaReferenciaFuncao = entidadeChamadaChamada as ReferenciaFuncao;
+                        return entidadeChamadaReferenciaFuncao.tipo;
+                    case 'Variavel':
+                        const entidadeChamadaVariavel = entidadeChamadaChamada as Variavel;
+                        return entidadeChamadaVariavel.tipo;
+                }
+
+                break;
+            case 'FuncaoConstruto':
+                const funcaoConstruto = inicializador as FuncaoConstruto;
+                return `função<${funcaoConstruto.tipo}>`;
+            case 'Leia':
+                return 'texto';
+            case 'Dupla':
+            case 'Trio':
+            case 'Quarteto':
+            case 'Quinteto':
+            case 'Sexteto':
+            case 'Septeto':
+            case 'Octeto':
+            case 'Noneto':
+            case 'Deceto':
+                return tipoDeDadosDelegua.TUPLA;
+            case "ImportarBiblioteca":
+            case "ModuloDeclaracoes":
+                return "módulo";
+            default:
+                return inicializador.tipo;
+        }
+    }
+
+    /**
+     * Após palavra reservada `seja`, é esperado ou uma variável, ou uma função.
+     * @returns Um Construto, ou do tipo `Var` para variável, ou do tipo `FuncaoDeclaracao` se for
+     *          declaração de função.
+     */
+    protected declaracaoDeVariaveisOuFuncoes(): Var | FuncaoDeclaracao {
+        const identificador = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome da variável ou função.');
+
+        if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO)) {
+            return this.declaracaoDeFuncao(identificador);
+        }
+
+        this.consumir(tiposDeSimbolos.IGUAL, "Esperado símbolo de igual após nome de identificador em declaração 'seja'.");
+
+        const inicializador = this.expressao();
+        const tipo = this.logicaComumInferenciaTiposVariaveis(inicializador);
+        this.pilhaEscopos.definirInformacoesVariavel(
+            identificador.lexema, 
+            new InformacaoVariavelOuConstante(identificador.lexema, tipo)
+        );
+
+        return new Var(identificador, inicializador, tipo);
+    }
+
+    protected logicaComumParametros(): ParametroInterface[] {
+        const parametros: ParametroInterface[] = [];
+
+        do {
+            const parametro: Partial<ParametroInterface> = {};
+
+            parametro.nome = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome do parâmetro.');
+
+            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) {
+                const valorPadrao = this.primario();
+                parametro.valorPadrao = valorPadrao;
+            }
+
+            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
+                let tipoDadoParametro = this.verificarDefinicaoTipoAtual();
+                parametro.tipoDado = tipoDadoParametro;
+                this.avancarEDevolverAnterior();
+            }
+
+            this.pilhaEscopos.definirInformacoesVariavel(
+                parametro.nome.lexema, 
+                new InformacaoVariavelOuConstante(parametro.nome.lexema, parametro.tipoDado || 'qualquer')
+            );
+
+            parametros.push(parametro as ParametroInterface);
+            if (parametro.abrangencia === 'multiplo') break;
+        } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
+        return parametros;
+    }
+
+    override corpoDaFuncao(tipo: 'função' | 'implícita'): FuncaoConstruto {
+        // O parêntese esquerdo aqui é o símbolo atual.
+        // Ele já foi lido neste ponto.
+        const parenteseEsquerdo = this.simbolos[this.atual];
+
+        let parametros = [];
+        if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PARENTESE_DIREITO)) {
+            parametros = this.logicaComumParametros();
+        }
+
+        this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após parâmetros.");
+        switch (tipo) {
+            case 'função':
+                this.consumir(tiposDeSimbolos.SUBTRACAO, "Esperado seta após fechamento de parênteses para declaração de função.");
+                this.consumir(tiposDeSimbolos.MAIOR, "Esperado seta após fechamento de parênteses para declaração de função.");
+                break;
+            case 'implícita':
+                this.consumir(tiposDeSimbolos.IGUAL, "Esperado sinal de igual após fechamento de parênteses para declaração de função.");
+                break;
+        }
+
+        const corpo = this.resolverDeclaracao() as Declaracao;
+        // Se o corpo for uma `Expressao`, corpo é convertido para `Retorna`.
+        // Tenda trabalha com retornos implícitos.
+        let corpoResolvido = [];
+        if (corpo.constructor.name === 'Expressao') {
+            const expressaoComoRetorna = new Retorna(
+                new Simbolo(tiposDeSimbolos.RETORNA, 'retorna', 'retorna', parenteseEsquerdo.linha, this.hashArquivo),
+                (corpo as Expressao).expressao
+            );
+            corpoResolvido.push(expressaoComoRetorna);
+        } else {
+            // TODO: Verificar se `corpo` é sempre um Array aqui.
+            corpoResolvido = corpo as unknown as Declaracao[];
+        }
+
+        // TODO: Inferir o tipo de retorno corretamente.
+        return new FuncaoConstruto(this.hashArquivo, Number(parenteseEsquerdo.linha), parametros, corpoResolvido, 'qualquer');
+    }
+
+    /**
+     * Até então, Tenda não tem casos de declarações fora de blocos.
+     * Isso pode mudar futuramente. Portanto, esta seção será mantida.
+     * @returns Uma `Declaracao` ou várias, dependendo do retorno de `resolverDeclaracao`.
+     * @see resolverDeclaracao
+     */
+    override resolverDeclaracaoForaDeBloco(): Declaracao | Declaracao[] {
+        try {
+            return this.resolverDeclaracao();
+        } catch (erro: any) {
+            this.sincronizar();
+            this.erros.push(erro);
+            return null;
+        }
+    }
+
+    /**
+     * Usado quando há erros na avaliação sintática.
+     * Garante que o código não entre em loop infinito.
+     * @returns Sempre retorna `void`.
+     */
+    protected sincronizar(): void {
+        this.avancarEDevolverAnterior();
+
+        while (!this.estaNoFinal()) {
+            const tipoSimboloAtual: string = this.simbolos[this.atual - 1].tipo;
+
+            switch (tipoSimboloAtual) {
+                case tiposDeSimbolos.CLASSE:
+                case tiposDeSimbolos.FUNCAO:
+                case tiposDeSimbolos.FUNÇÃO:
+                case tiposDeSimbolos.VARIAVEL:
+                case tiposDeSimbolos.PARA:
+                case tiposDeSimbolos.SE:
+                case tiposDeSimbolos.ENQUANTO:
+                case tiposDeSimbolos.EXIBA:
+                case tiposDeSimbolos.RETORNA:
+                    return;
+            }
+
+            this.avancarEDevolverAnterior();
+        }
+    }
+
+    /**
+     * Inicializa o primeiro nível da pilha de escopos, normalmente com ítens da biblioteca global.
+     * TODO: Esta abordagem deve ser depreciada, em favor do novo suporte a referências de funções.
+     */
+    protected inicializarPilhaEscopos() {
+        this.pilhaEscopos = new PilhaEscopos();
+        this.pilhaEscopos.empilhar(new InformacaoEscopo());
+
+        // Funções nativas de Delégua
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'aleatorio', 
+            new InformacaoVariavelOuConstante('aleatorio', 'inteiro', [
+                new InformacaoVariavelOuConstante('número', 'número')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'aleatorioEntre', 
+            new InformacaoVariavelOuConstante('aleatorioEntre', 'inteiro', [
+                new InformacaoVariavelOuConstante('minimo', 'número'),
+                new InformacaoVariavelOuConstante('maximo', 'número')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'algum',
+            new InformacaoVariavelOuConstante('algum', 'lógico', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'encontrar',
+            new InformacaoVariavelOuConstante('encontrar', 'qualquer', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'encontrarIndice',
+            new InformacaoVariavelOuConstante('encontrarIndice', 'inteiro', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'encontrarUltimo',
+            new InformacaoVariavelOuConstante('encontrarUltimo', 'inteiro', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'encontrarUltimoIndice',
+            new InformacaoVariavelOuConstante('encontrarUltimoIndice', 'inteiro', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'filtrarPor', 
+            new InformacaoVariavelOuConstante('filtrarPor', 'qualquer[]', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoFiltragem', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'incluido',
+            new InformacaoVariavelOuConstante('incluido', 'lógico', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('valor', 'qualquer')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'inteiro', 
+            new InformacaoVariavelOuConstante('inteiro', 'inteiro', [
+                new InformacaoVariavelOuConstante('valor', 'qualquer')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'mapear', 
+            new InformacaoVariavelOuConstante('mapear', 'qualquer[]', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoMapeamento', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'numero', 
+            new InformacaoVariavelOuConstante('número', 'número', [
+                new InformacaoVariavelOuConstante('valorParaConverter', 'qualquer')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'número', new InformacaoVariavelOuConstante('número', 'número', [
+                new InformacaoVariavelOuConstante('valorParaConverter', 'qualquer')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'ordenar', 
+            new InformacaoVariavelOuConstante('ordenar', 'qualquer[]', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoOrdenacao', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'paraCada', 
+            new InformacaoVariavelOuConstante('paraCada', 'qualquer[]', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoFiltragem', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'primeiroEmCondicao', 
+            new InformacaoVariavelOuConstante('primeiroEmCondicao', 'qualquer', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoFiltragem', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'real', new InformacaoVariavelOuConstante('real', 'número', [
+                new InformacaoVariavelOuConstante('valorParaConverter', 'qualquer')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'reduzir',
+            new InformacaoVariavelOuConstante('reduzir', 'qualquer', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoReducao', 'função'),
+                new InformacaoVariavelOuConstante('valorInicial', 'qualquer')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'tamanho', 
+            new InformacaoVariavelOuConstante('tamanho', 'inteiro', [
+                new InformacaoVariavelOuConstante('objeto', 'qualquer')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'texto', 
+            new InformacaoVariavelOuConstante('texto', 'texto', [
+                new InformacaoVariavelOuConstante('valorParaConverter', 'qualquer')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'todosEmCondicao', 
+            new InformacaoVariavelOuConstante('todosEmCondicao', 'lógico', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
+                new InformacaoVariavelOuConstante('funcaoCondicional', 'função')
+            ])
+        );
+        this.pilhaEscopos.definirInformacoesVariavel(
+            'tupla', 
+            new InformacaoVariavelOuConstante('tupla', 'tupla', [
+                new InformacaoVariavelOuConstante('vetor', 'qualquer[]')
+            ])
+        );
+
+        // TODO: Escrever algum tipo de validação aqui.
+        for (const tipos of Object.values(this.tiposDeFerramentasExternas)) {
+            for (const [nomeTipo, tipo] of Object.entries(tipos)) {
+                this.pilhaEscopos.definirInformacoesVariavel(
+                    nomeTipo,
+                    new InformacaoVariavelOuConstante(nomeTipo, tipo)
+                );
+            }
+        }
+    }
+
+    analisar(
+        retornoLexador: RetornoLexador<SimboloInterface>,
+        hashArquivo: number
+    ): RetornoAvaliadorSintatico<Declaracao> {
+        const inicioAnalise: [number, number] = hrtime();
+        this.erros = [];
+        this.atual = 0;
+        this.blocos = 0;
+
+        this.hashArquivo = hashArquivo || 0;
+        this.simbolos = retornoLexador?.simbolos || [];
+        this.tiposDefinidosEmCodigo = {};
+        this.inicializarPilhaEscopos();
+
+        let declaracoes: Declaracao[] = [];
+        while (!this.estaNoFinal()) {
+            const retornoDeclaracao = this.resolverDeclaracaoForaDeBloco();
+            if (Array.isArray(retornoDeclaracao)) {
+                declaracoes = declaracoes.concat(retornoDeclaracao);
+            } else if (retornoDeclaracao !== null) {
+                declaracoes.push(retornoDeclaracao as Declaracao);
+            }
+        }
+
+        if (this.performance) {
+            const deltaAnalise: [number, number] = hrtime(inicioAnalise);
+            // eslint-disable-next-line no-undef
+            console.log(`[Avaliador Sintático Tenda] Tempo para análise: ${deltaAnalise[0] * 1e9 + deltaAnalise[1]}ns`);
+        }
+
+        return {
+            declaracoes: declaracoes,
+            erros: this.erros,
+        } as RetornoAvaliadorSintatico<Declaracao>;
+    }
+}
diff --git a/fontes/avaliador-sintatico/dialetos/index.ts b/fontes/avaliador-sintatico/dialetos/index.ts
index d6da852f..846a90e1 100644
--- a/fontes/avaliador-sintatico/dialetos/index.ts
+++ b/fontes/avaliador-sintatico/dialetos/index.ts
@@ -1,3 +1,4 @@
 export * from './avaliador-sintatico-egua-classico';
 export * from './avaliador-sintatico-pitugues';
 export * from './avaliador-sintatico-portugol-ipt';
+export * from './avaliador-sintatico-tenda';
diff --git a/fontes/lexador/dialetos/index.ts b/fontes/lexador/dialetos/index.ts
index 062dc924..8583c025 100644
--- a/fontes/lexador/dialetos/index.ts
+++ b/fontes/lexador/dialetos/index.ts
@@ -2,3 +2,4 @@ export * from './lexador-egua-classico';
 export * from './lexador-pitugues';
 export * from './lexador-guarani';
 export * from './lexador-portugol-ipt';
+export * from './lexador-tenda';
diff --git a/fontes/lexador/dialetos/lexador-tenda.ts b/fontes/lexador/dialetos/lexador-tenda.ts
new file mode 100644
index 00000000..4682c025
--- /dev/null
+++ b/fontes/lexador/dialetos/lexador-tenda.ts
@@ -0,0 +1,470 @@
+import hrtime from 'browser-process-hrtime';
+
+import { LexadorInterface, SimboloInterface } from '../../interfaces';
+import { Simbolo } from '../simbolo';
+import { palavrasReservadas } from './palavras-reservadas/tenda';
+import { ErroLexador } from '../erro-lexador';
+import { RetornoLexador } from '../../interfaces/retornos/retorno-lexador';
+import { Pragma } from './pragma';
+
+import tiposDeSimbolos from '../../tipos-de-simbolos/tenda';
+
+/**
+ * O Lexador é responsável por transformar o código em uma coleção de tokens de linguagem.
+ * Cada token de linguagem é representado por um tipo, um lexema e informações da linha de código em que foi expresso.
+ * Também é responsável por mapear as palavras reservadas da linguagem, que não podem ser usadas por outras
+ * estruturas, tais como nomes de variáveis, funções, literais, classes e assim por diante.
+ *
+ * Este lexador é diferente dos demais, porque também produz uma estrutura de dados de pragmas, que explica,
+ * por exemplo quantos espaços há na frente de cada linha. Assim como a linguagem Python, os blocos de
+ * escopo são definidos pelo número de espaços à frente do código.
+ */
+export class LexadorTenda implements LexadorInterface<SimboloInterface> {
+    codigo: string[];
+    hashArquivo: number;
+    simbolos: SimboloInterface[];
+    erros: ErroLexador[];
+    pragmas: { [linha: number]: Pragma };
+
+    inicioSimbolo: number;
+    atual: number;
+    linha: number;
+    performance: boolean;
+
+    constructor(performance = false) {
+        this.performance = performance;
+
+        this.simbolos = [];
+        this.erros = [];
+        this.pragmas = {};
+
+        this.inicioSimbolo = 0;
+        this.atual = 0;
+        this.linha = 0;
+    }
+
+    eDigito(caractere: string): boolean {
+        return caractere >= '0' && caractere <= '9';
+    }
+
+    eAlfabeto(caractere: string): boolean {
+        const acentuacoes = [
+            'á',
+            'Á',
+            'ã',
+            'Ã',
+            'â',
+            'Â',
+            'à',
+            'À',
+            'é',
+            'É',
+            'ê',
+            'Ê',
+            'í',
+            'Í',
+            'ó',
+            'Ó',
+            'õ',
+            'Õ',
+            'ô',
+            'Ô',
+            'ú',
+            'Ú',
+            'ç',
+            'Ç',
+            '_',
+        ];
+
+        return (
+            (caractere >= 'a' && caractere <= 'z') ||
+            (caractere >= 'A' && caractere <= 'Z') ||
+            acentuacoes.includes(caractere)
+        );
+    }
+
+    eAlfabetoOuDigito(caractere: string): boolean {
+        return this.eDigito(caractere) || this.eAlfabeto(caractere);
+    }
+
+    /**
+     * Indica se o código está na última linha.
+     * @returns Verdadeiro se contador de linhas está na última linha.
+     *          Falso caso contrário.
+     */
+    eUltimaLinha(): boolean {
+        return this.linha >= this.codigo.length - 1;
+    }
+
+    eFinalDaLinha(): boolean {
+        return this.atual >= this.codigo[this.linha].length;
+    }
+
+    eFinalDoCodigo(): boolean {
+        if (this.linha > this.codigo.length - 1) return true;
+        return this.linha == this.codigo.length - 1 && this.codigo[this.codigo.length - 1].length <= this.atual;
+    }
+
+    avancar(): void {
+        this.atual += 1;
+
+        if (this.eFinalDaLinha() && !this.eUltimaLinha()) {
+            this.linha++;
+            this.atual = 0;
+            // this.logicaEmLinhaIniciada = false;
+            this.analisarIndentacao();
+        }
+    }
+
+    adicionarSimbolo(tipo: any, literal: any = null): void {
+        const texto: string = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
+        this.simbolos.push(new Simbolo(tipo, texto, literal, this.linha + 1, this.hashArquivo));
+    }
+
+    simboloAtual(): string {
+        if (this.eFinalDaLinha()) return '\0';
+        if (this.linha > this.codigo.length - 1) return '\0';
+        return this.codigo[this.linha].charAt(this.atual);
+    }
+
+    proximoSimbolo(): string {
+        if (this.atual + 1 >= this.codigo[this.linha].length) return '\0';
+        return this.codigo[this.linha].charAt(this.atual + 1);
+    }
+
+    simboloAnterior(): string {
+        return this.codigo[this.linha].charAt(this.atual - 1);
+    }
+
+    analisarTexto(delimitador = '"'): void {
+        const linhaPrimeiroCaracter: number = this.linha;
+        while (this.simboloAtual() !== delimitador && !this.eFinalDoCodigo()) {
+            this.avancar();
+        }
+
+        if (this.eFinalDoCodigo()) {
+            this.erros.push({
+                linha: this.linha + 1,
+                caractere: this.simboloAnterior(),
+                mensagem: 'Texto não finalizado.',
+            } as ErroLexador);
+            return;
+        }
+
+        const textoCompleto = this.codigo[this.linha].substring(this.inicioSimbolo + 1, this.atual);
+
+        this.simbolos.push(
+            new Simbolo(
+                tiposDeSimbolos.TEXTO,
+                textoCompleto,
+                textoCompleto,
+                linhaPrimeiroCaracter + 1,
+                this.hashArquivo
+            )
+        );
+    }
+
+    analisarNumero(): void {
+        const linhaPrimeiroDigito: number = this.linha;
+        while (this.eDigito(this.simboloAtual()) && this.linha === linhaPrimeiroDigito) {
+            this.avancar();
+        }
+
+        if (this.simboloAtual() == '.' && this.eDigito(this.proximoSimbolo())) {
+            this.avancar();
+
+            while (this.eDigito(this.simboloAtual())) {
+                this.avancar();
+            }
+        }
+
+        let numeroCompleto: string;
+        if (linhaPrimeiroDigito < this.linha) {
+            const linhaNumero: string = this.codigo[linhaPrimeiroDigito];
+            numeroCompleto = linhaNumero.substring(this.inicioSimbolo, linhaNumero.length);
+        } else {
+            numeroCompleto = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
+        }
+
+        this.simbolos.push(
+            new Simbolo(
+                tiposDeSimbolos.NUMERO,
+                numeroCompleto,
+                parseFloat(numeroCompleto),
+                linhaPrimeiroDigito + 1,
+                this.hashArquivo
+            )
+        );
+    }
+
+    identificarPalavraChave(): void {
+        const linhaPrimeiroCaracter: number = this.linha;
+        while (this.eAlfabetoOuDigito(this.simboloAtual()) && this.linha === linhaPrimeiroCaracter) {
+            this.avancar();
+        }
+
+        let textoPalavraChave: string;
+        if (linhaPrimeiroCaracter < this.linha) {
+            const linhaPalavraChave: string = this.codigo[linhaPrimeiroCaracter];
+            textoPalavraChave = linhaPalavraChave.substring(this.inicioSimbolo, linhaPalavraChave.length);
+        } else {
+            textoPalavraChave = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
+        }
+
+        const tipo: string =
+            textoPalavraChave in palavrasReservadas
+                ? palavrasReservadas[textoPalavraChave]
+                : tiposDeSimbolos.IDENTIFICADOR;
+
+        this.simbolos.push(new Simbolo(tipo, textoPalavraChave, null, linhaPrimeiroCaracter + 1, this.hashArquivo));
+    }
+
+    analisarIndentacao(): void {
+        let espacos = 0;
+        while (['\t', ' '].includes(this.simboloAtual()) && !this.eFinalDoCodigo()) {
+            espacos++;
+            this.avancar();
+        }
+
+        this.pragmas[this.linha + 1] = {
+            linha: this.linha + 1,
+            espacosIndentacao: espacos,
+        };
+    }
+
+    avancarParaProximaLinha(): void {
+        this.linha++;
+        this.atual = 0;
+        this.analisarIndentacao();
+    }
+
+    analisarToken(): void {
+        const caractere = this.simboloAtual();
+
+        switch (caractere) {
+            case ' ':
+            case '\t':
+                this.avancar();
+
+                break;
+            case '\r':
+            case '\n':
+            case '\0':
+            case ';':
+                this.avancar();
+                break;
+
+            case '=':
+                this.avancar();
+                if (this.simboloAtual() === '=') {
+                    this.adicionarSimbolo(tiposDeSimbolos.IGUAL_IGUAL);
+                    this.avancar();
+                } else {
+                    this.adicionarSimbolo(tiposDeSimbolos.IGUAL);
+                }
+
+                break;
+
+            case '#':
+                this.avancarParaProximaLinha();
+                break;
+
+            case '[':
+                this.adicionarSimbolo(tiposDeSimbolos.COLCHETE_ESQUERDO);
+                this.avancar();
+                break;
+            case ']':
+                this.adicionarSimbolo(tiposDeSimbolos.COLCHETE_DIREITO);
+                this.avancar();
+                break;
+            case '(':
+                this.adicionarSimbolo(tiposDeSimbolos.PARENTESE_ESQUERDO);
+                this.avancar();
+                break;
+            case ')':
+                this.adicionarSimbolo(tiposDeSimbolos.PARENTESE_DIREITO);
+                this.avancar();
+                break;
+            case '{':
+                this.adicionarSimbolo(tiposDeSimbolos.CHAVE_ESQUERDA);
+                this.avancar();
+                break;
+            case '}':
+                this.adicionarSimbolo(tiposDeSimbolos.CHAVE_DIREITA);
+                this.avancar();
+                break;
+            case ',':
+                this.adicionarSimbolo(tiposDeSimbolos.VIRGULA);
+                this.avancar();
+                break;
+            case '.':
+                this.adicionarSimbolo(tiposDeSimbolos.PONTO);
+                this.avancar();
+                break;
+            case '-':
+                this.avancar();
+                if (this.simboloAtual() === '=') {
+                    this.adicionarSimbolo(tiposDeSimbolos.MENOS_IGUAL);
+                    this.avancar();
+                } else {
+                    this.adicionarSimbolo(tiposDeSimbolos.SUBTRACAO);
+                }
+
+                break;
+            case '+':
+                this.avancar();
+                if (this.simboloAtual() === '=') {
+                    this.adicionarSimbolo(tiposDeSimbolos.MAIS_IGUAL);
+                    this.avancar();
+                } else {
+                    this.adicionarSimbolo(tiposDeSimbolos.ADICAO);
+                }
+                break;
+
+            case '/':
+                this.avancar();
+                switch (this.simboloAtual()) {
+                    case '/':
+                        this.adicionarSimbolo(tiposDeSimbolos.DIVISAO_INTEIRA);
+                        this.avancar();
+                        break;
+                    default:
+                        this.adicionarSimbolo(tiposDeSimbolos.DIVISAO);
+                        break;
+                }
+
+                break;
+
+            case ':':
+                this.adicionarSimbolo(tiposDeSimbolos.DOIS_PONTOS);
+                this.avancar();
+                break;
+
+            case '%':
+                this.adicionarSimbolo(tiposDeSimbolos.MODULO);
+                this.avancar();
+                break;
+            case '*':
+                this.inicioSimbolo = this.atual;
+                this.avancar();
+                if (this.simboloAtual() === '*') {
+                    this.avancar();
+                    this.adicionarSimbolo(tiposDeSimbolos.EXPONENCIACAO);
+                } else {
+                    this.adicionarSimbolo(tiposDeSimbolos.MULTIPLICACAO);
+                }
+
+                break;
+            case '!':
+                this.avancar();
+                if (this.simboloAtual() === '=') {
+                    this.adicionarSimbolo(tiposDeSimbolos.DIFERENTE);
+                    this.avancar();
+                } else {
+                    this.adicionarSimbolo(tiposDeSimbolos.NEGACAO);
+                }
+
+            case '&':
+                this.adicionarSimbolo(tiposDeSimbolos.BIT_AND);
+                this.avancar();
+                break;
+
+            case '~':
+                this.adicionarSimbolo(tiposDeSimbolos.BIT_NOT);
+                this.avancar();
+                break;
+
+            case '|':
+                this.adicionarSimbolo(tiposDeSimbolos.BIT_OR);
+                this.avancar();
+                break;
+
+            case '^':
+                this.adicionarSimbolo(tiposDeSimbolos.BIT_XOR);
+                this.avancar();
+                break;
+
+            case '<':
+                this.avancar();
+                if (this.simboloAtual() === '=') {
+                    this.adicionarSimbolo(tiposDeSimbolos.MENOR_IGUAL);
+                    this.avancar();
+                } else if (this.simboloAtual() === '<') {
+                    this.adicionarSimbolo(tiposDeSimbolos.MENOR_MENOR);
+                    this.avancar();
+                } else {
+                    this.adicionarSimbolo(tiposDeSimbolos.MENOR);
+                }
+                break;
+
+            case '>':
+                this.avancar();
+                if (this.simboloAtual() === '=') {
+                    this.adicionarSimbolo(tiposDeSimbolos.MAIOR_IGUAL);
+                    this.avancar();
+                } else if (this.simboloAtual() === '>') {
+                    this.adicionarSimbolo(tiposDeSimbolos.MAIOR_MAIOR);
+                    this.avancar();
+                } else {
+                    this.adicionarSimbolo(tiposDeSimbolos.MAIOR);
+                }
+                break;
+
+            case '"':
+                this.avancar();
+                this.analisarTexto('"');
+                this.avancar();
+                break;
+
+            case "'":
+                this.avancar();
+                this.analisarTexto("'");
+                this.avancar();
+                break;
+
+            default:
+                if (this.eDigito(caractere)) this.analisarNumero();
+                else if (this.eAlfabeto(caractere)) this.identificarPalavraChave();
+                else {
+                    this.erros.push({
+                        linha: this.linha + 1,
+                        caractere: caractere,
+                        mensagem: 'Caractere inesperado.',
+                    } as ErroLexador);
+                    this.avancar();
+                }
+        }
+    }
+
+    mapear(codigo: string[], hashArquivo: number): RetornoLexador<SimboloInterface> {
+        const inicioMapeamento: [number, number] = hrtime();
+        this.simbolos = [];
+        this.erros = [];
+        this.pragmas = {};
+
+        this.inicioSimbolo = 0;
+        this.atual = 0;
+        this.linha = 0;
+
+        this.codigo = codigo || [''];
+        this.hashArquivo = hashArquivo;
+        // Análise de indentação da primeira linha.
+        this.analisarIndentacao();
+
+        while (!this.eFinalDoCodigo()) {
+            this.inicioSimbolo = this.atual;
+            this.analisarToken();
+        }
+
+        if (this.performance) {
+            const deltaMapeamento: [number, number] = hrtime(inicioMapeamento);
+            console.log(`[Lexador] Tempo para mapeamento: ${deltaMapeamento[0] * 1e9 + deltaMapeamento[1]}ns`);
+        }
+
+        return {
+            simbolos: this.simbolos,
+            erros: this.erros,
+            pragmas: this.pragmas,
+        } as RetornoLexador<SimboloInterface>;
+    }
+}
diff --git a/fontes/lexador/dialetos/palavras-reservadas/tenda.ts b/fontes/lexador/dialetos/palavras-reservadas/tenda.ts
new file mode 100644
index 00000000..7a16ce5b
--- /dev/null
+++ b/fontes/lexador/dialetos/palavras-reservadas/tenda.ts
@@ -0,0 +1,47 @@
+import tiposDeSimbolos from '../../../tipos-de-simbolos/tenda';
+
+export const palavrasReservadas = {
+    até: tiposDeSimbolos.ATÉ,
+    cada: tiposDeSimbolos.CADA,
+    caso: tiposDeSimbolos.CASO,
+    classe: tiposDeSimbolos.CLASSE,
+    como: tiposDeSimbolos.COMO,
+    construtor: tiposDeSimbolos.CONSTRUTOR,
+    continua: tiposDeSimbolos.CONTINUA,
+    e: tiposDeSimbolos.E,
+    é: tiposDeSimbolos.É,
+    em: tiposDeSimbolos.EM,
+    então: tiposDeSimbolos.ENTÃO,
+    enquanto: tiposDeSimbolos.ENQUANTO,
+    escolha: tiposDeSimbolos.ESCOLHA,
+    exiba: tiposDeSimbolos.EXIBA,
+    falhar: tiposDeSimbolos.FALHAR,
+    falso: tiposDeSimbolos.FALSO,
+    faça: tiposDeSimbolos.FAÇA,
+    fazer: tiposDeSimbolos.FAZER,
+    fim: tiposDeSimbolos.FIM,
+    finalmente: tiposDeSimbolos.FINALMENTE,
+    fixo: tiposDeSimbolos.CONSTANTE,
+    função: tiposDeSimbolos.FUNÇÃO,
+    herda: tiposDeSimbolos.HERDA,
+    importar: tiposDeSimbolos.IMPORTAR,
+    isto: tiposDeSimbolos.ISTO,
+    leia: tiposDeSimbolos.LEIA,
+    não: tiposDeSimbolos.NÃO,
+    nulo: tiposDeSimbolos.NADA,
+    ou: tiposDeSimbolos.OU,
+    padrao: tiposDeSimbolos.PADRAO,
+    para: tiposDeSimbolos.PARA,
+    pegue: tiposDeSimbolos.PEGUE,
+    retorna: tiposDeSimbolos.RETORNA,
+    se: tiposDeSimbolos.SE,
+    seja: tiposDeSimbolos.SEJA,
+    senão: tiposDeSimbolos.SENÃO,
+    super: tiposDeSimbolos.SUPER,
+    sustar: tiposDeSimbolos.SUSTAR,
+    tem: tiposDeSimbolos.TEM,
+    tendo: tiposDeSimbolos.TENDO,
+    tente: tiposDeSimbolos.TENTE,
+    tipo: tiposDeSimbolos.TIPO,
+    verdadeiro: tiposDeSimbolos.VERDADEIRO,
+};
diff --git a/fontes/tipos-de-simbolos/tenda.ts b/fontes/tipos-de-simbolos/tenda.ts
new file mode 100644
index 00000000..0b953465
--- /dev/null
+++ b/fontes/tipos-de-simbolos/tenda.ts
@@ -0,0 +1,99 @@
+// Em Tenda, isto é implementado em https://github.com/gabrielbrunop/tenda/blob/main/crates/scanner/src/token.rs#L42.
+export default {
+    ADICAO: 'ADICAO',
+    ARROBA: 'ARROBA',
+    ATÉ: 'ATÉ',
+    BIT_AND: 'BIT_AND',
+    BIT_OR: 'BIT_OR',
+    BIT_XOR: 'BIT_XOR',
+    BIT_NOT: 'BIT_NOT',
+    CADA: 'CADA',
+    CASO: 'CASO',
+    CHAVE_DIREITA: 'CHAVE_DIREITA',
+    CHAVE_ESQUERDA: 'CHAVE_ESQUERDA',
+    CLASSE: 'CLASSE',
+    COLCHETE_DIREITO: 'COLCHETE_DIREITO',
+    COLCHETE_ESQUERDO: 'COLCHETE_ESQUERDO',
+    COMENTARIO: 'COMENTARIO',
+    COMO: 'COMO',
+    CONSTANTE: 'CONSTANTE',
+    CONSTRUTOR: 'CONSTRUTOR',
+    CONTINUA: 'CONTINUA',
+    DECREMENTAR: 'DECREMENTAR',
+    DIFERENTE: 'DIFERENTE',
+    DIVISAO: 'DIVISAO',
+    DIVISAO_IGUAL: 'DIVISAO_IGUAL',
+    DIVISAO_INTEIRA: 'DIVISAO_INTEIRA',
+    DIVISAO_INTEIRA_IGUAL: 'DIVISAO_INTEIRA_IGUAL',
+    DOIS_PONTOS: 'DOIS_PONTOS',
+    E: 'E',
+    É: 'É',
+    EM: 'EM',
+    ENTÃO: 'ENTÃO',
+    ENQUANTO: 'ENQUANTO',
+    EOF: 'EOF',
+    ESCOLHA: 'ESCOLHA',
+    EXIBA: 'EXIBA',
+    EXPONENCIACAO: 'EXPONENCIACAO',
+    EXPRESSAO_REGULAR: 'EXPRESSAO_REGULAR',
+    FALHAR: 'FALHAR',
+    FALSO: 'FALSO',
+    FAÇA: 'FAÇA',
+    FAZER: 'FAZER',
+    FIM: 'FIM',
+    FINALMENTE: 'FINALMENTE',
+    FUNCAO: 'FUNCAO',
+    FUNÇÃO: 'FUNÇÃO',
+    HERDA: 'HERDA',
+    IDENTIFICADOR: 'IDENTIFICADOR',
+    IGUAL: 'IGUAL',
+    IGUAL_IGUAL: 'IGUAL_IGUAL',
+    IMPORTAR: 'IMPORTAR',
+    INCREMENTAR: 'INCREMENTAR',
+    ISTO: 'ISTO',
+    LEIA: 'LEIA',
+    LINHA_COMENTARIO: 'LINHA_COMENTARIO',
+    MAIOR: 'MAIOR',
+    MAIOR_IGUAL: 'MAIOR_IGUAL',
+    MAIOR_MAIOR: 'MAIOR_MAIOR',
+    MAIS_IGUAL: 'MAIS_IGUAL',
+    MENOR: 'MENOR',
+    MENOR_IGUAL: 'MENOR_IGUAL',
+    MENOR_MENOR: 'MENOR_MENOR',
+    MENOS_IGUAL: 'MENOS_IGUAL',
+    MODULO: 'MODULO',
+    MODULO_IGUAL: 'MODULO_IGUAL',
+    MULTIPLICACAO: 'MULTIPLICACAO',
+    MULTIPLICACAO_IGUAL: 'MULTIPLICACAO_IGUAL',
+    NADA: 'NADA',
+    NÃO: 'NÃO',
+    NEGACAO: 'NEGACAO',
+    NUMERO: 'NUMERO',
+    NÚMERO: 'NÚMERO',
+    OU: 'OU',
+    PADRAO: 'PADRAO',
+    PADRÃO: 'PADRÃO',
+    PARA: 'PARA',
+    PARENTESE_DIREITO: 'PARENTESE_DIREITO',
+    PARENTESE_ESQUERDO: 'PARENTESE_ESQUERDO',
+    PAUSA: 'PAUSA',
+    PEGUE: 'PEGUE',
+    PONTO: 'PONTO',
+    PONTO_E_VIRGULA: 'PONTO_E_VIRGULA',
+    RETORNA: 'RETORNA',
+    SUBTRACAO: 'SUBTRACAO',
+    SE: 'SE',
+    SEJA: 'SEJA',
+    SENAO: 'SENAO',
+    SENÃO: 'SENÃO',
+    SUPER: 'SUPER',
+    SUSTAR: 'SUSTAR',
+    TEM: 'TEM',
+    TENDO: 'TENDO',
+    TENTE: 'TENTE',
+    TEXTO: 'TEXTO',
+    TIPO: 'TIPO',
+    VARIAVEL: 'VARIAVEL',
+    VERDADEIRO: 'VERDADEIRO',
+    VIRGULA: 'VIRGULA',
+}
diff --git a/fontes/tradutores/index.ts b/fontes/tradutores/index.ts
index 9f0e3fdd..86a1280a 100644
--- a/fontes/tradutores/index.ts
+++ b/fontes/tradutores/index.ts
@@ -5,3 +5,4 @@ export * from './tradutor-portugol-ipt';
 export * from './tradutor-python';
 export * from './tradutor-reverso-javascript';
 export * from './tradutor-reverso-python';
+export * from './tradutor-reverso-tenda';
diff --git a/fontes/tradutores/tradutor-reverso-tenda.ts b/fontes/tradutores/tradutor-reverso-tenda.ts
new file mode 100644
index 00000000..05a3a3c0
--- /dev/null
+++ b/fontes/tradutores/tradutor-reverso-tenda.ts
@@ -0,0 +1,749 @@
+import {
+    AcessoIndiceVariavel,
+    AcessoMetodo,
+    AcessoMetodoOuPropriedade,
+    Agrupamento,
+    ArgumentoReferenciaFuncao,
+    AtribuicaoPorIndice,
+    Atribuir,
+    Binario,
+    Chamada,
+    Construto,
+    DefinirValor,
+    Dicionario,
+    FimPara,
+    FuncaoConstruto,
+    Isto,
+    Leia,
+    Literal,
+    Logico,
+    ReferenciaFuncao,
+    TipoDe,
+    Unario,
+    Variavel,
+    Vetor,
+} from '../construtos';
+import {
+    Bloco,
+    Classe,
+    Comentario,
+    Const,
+    Declaracao,
+    Enquanto,
+    Escreva,
+    Expressao,
+    FuncaoDeclaracao,
+    Para,
+    ParaCada,
+    Retorna,
+    Se,
+    Tente,
+    Var,
+} from '../declaracoes';
+import { SimboloInterface, TradutorInterface } from '../interfaces';
+
+import tiposDeSimbolos from '../tipos-de-simbolos/tenda';
+
+export class TradutorReversoTenda implements TradutorInterface<Declaracao> {
+    indentacao: number = 0;
+
+    traduzirSimboloOperador(operador: SimboloInterface): string {
+        switch (operador.tipo) {
+            case tiposDeSimbolos.ADICAO:
+                return '+';
+            case tiposDeSimbolos.BIT_AND:
+                return '&';
+            case tiposDeSimbolos.BIT_OR:
+                return '|';
+            case tiposDeSimbolos.BIT_XOR:
+                return '^';
+            case tiposDeSimbolos.BIT_NOT:
+                return '~';
+            case tiposDeSimbolos.DIFERENTE:
+                return '!=';
+            case tiposDeSimbolos.DIVISAO:
+                return '/';
+            case tiposDeSimbolos.E:
+                return 'e';
+            case tiposDeSimbolos.EXPONENCIACAO:
+                return '**';
+            case tiposDeSimbolos.IGUAL:
+                return '=';
+            case tiposDeSimbolos.É:
+                return '==';
+            case tiposDeSimbolos.MAIOR:
+                return '>';
+            case tiposDeSimbolos.MAIOR_IGUAL:
+                return '>=';
+            case tiposDeSimbolos.MENOR:
+                return '<';
+            case tiposDeSimbolos.MENOR_IGUAL:
+                return '<=';
+            case tiposDeSimbolos.MODULO:
+                return '%';
+            case tiposDeSimbolos.MULTIPLICACAO:
+                return '*';
+            case tiposDeSimbolos.NÃO:
+                return '!';
+            case tiposDeSimbolos.OU:
+                return 'ou';
+            case tiposDeSimbolos.SUBTRACAO:
+                return '-';
+        }
+    }
+
+    traduzirFuncaoOuMetodo(nomeMetodo: string, objetoResolvido: string, argumentos: Construto[]): string {
+        if (argumentos === undefined) {
+            return `${objetoResolvido}.${nomeMetodo}`;
+        }
+
+        const argumentosResolvidos: string[] = [];
+        for (const argumento of argumentos) {
+            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
+            argumentosResolvidos.push(argumentoResolvido);
+        }
+
+        let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
+        textoArgumentos = textoArgumentos.slice(0, -2);
+
+        switch (nomeMetodo) {
+            case 'adicionar':
+            case 'empilhar':
+                return `${objetoResolvido}.push(${textoArgumentos})`;
+            case 'fatiar':
+                return `${objetoResolvido}.slice(${argumentos[0]}, ${argumentos[1]})`;
+            case 'inclui':
+                return `${objetoResolvido}.includes(${argumentosResolvidos[0]})`;
+            case 'inverter':
+                return `${objetoResolvido}.toReversed()`;
+            case 'juntar':
+                return `${argumentosResolvidos[0]}.join(${objetoResolvido})`;
+            case 'maiusculo':
+                return `${objetoResolvido}.toUpperCase()`;
+            case 'mapear':
+                return `${objetoResolvido}.map(${this.traduzirFuncaoAnonimaParaLambda(argumentos[0])})`;
+            case 'minusculo':
+                return `${objetoResolvido}.toLowerCase()`;
+            case 'ordenar':
+                return `${objetoResolvido}.sort()`;
+            case 'remover':
+                return `delete ${objetoResolvido}[${argumentosResolvidos[0]}]`;
+            case 'removerPrimeiro':
+                return `${objetoResolvido}.shift()`;
+            case 'removerUltimo':
+                return `${objetoResolvido}.pop()`;
+            case 'somar':
+                return `${objetoResolvido}.reduce((acumulador, valorAtual) => acumulador + valorAtual, 0)`;
+            case 'tamanho':
+                return `${objetoResolvido}.length`;
+        }
+
+        return `${objetoResolvido}.${nomeMetodo}(${textoArgumentos}))`;
+    }
+
+    traduzirConstrutoAgrupamento(agrupamento: Agrupamento): string {
+        return this.dicionarioConstrutos[agrupamento.constructor.name](agrupamento.expressao || agrupamento);
+    }
+
+    traduzirConstrutoAtribuir(atribuir: Atribuir): string {
+        let resultado = this.dicionarioConstrutos[atribuir.alvo.constructor.name](atribuir.alvo);
+        const operador = atribuir.simboloOperador?.lexema || '=';
+
+        // Em Delégua, atribuições com operações embutidas devolvem um construto `Binario` no valor
+        // por várias razões, sendo a mais importante delas a lógica de interpretação.
+        let valorResolvido = '';
+        if (atribuir.simboloOperador && atribuir.valor.constructor.name === 'Binario') {
+            valorResolvido = this.dicionarioConstrutos[atribuir.valor.direita.constructor.name](atribuir.valor.direita);
+        } else {
+            valorResolvido = this.dicionarioConstrutos[atribuir.valor.constructor.name](atribuir.valor);
+        }
+
+        resultado += ` ${operador} ` + valorResolvido;
+        return resultado;
+    }
+
+    traduzirConstrutoBinario(binario: Binario): string {
+        let resultado = '';
+        // if (binario.esquerda.constructor.name === 'Agrupamento')
+        //     resultado += '(' + this.dicionarioConstrutos[binario.esquerda.constructor.name](binario.esquerda) + ')';
+        // else 
+        resultado += this.dicionarioConstrutos[binario.esquerda.constructor.name](binario.esquerda);
+
+        let operador = this.traduzirSimboloOperador(binario.operador);
+        resultado += ` ${operador} `;
+
+        // if (binario.direita.constructor.name === 'Agrupamento')
+            // resultado += '(' + this.dicionarioConstrutos[binario.direita.constructor.name](binario.direita) + ')';
+        // else 
+        resultado += this.dicionarioConstrutos[binario.direita.constructor.name](binario.direita);
+
+        return resultado;
+    }
+
+    traduzirConstrutoChamada(chamada: Chamada): string {
+        let resultado = '';
+
+        const retorno = `${this.dicionarioConstrutos[chamada.entidadeChamada.constructor.name](
+            chamada.entidadeChamada,
+            chamada.argumentos
+        )}`;
+
+        resultado += retorno;
+        return resultado;
+    }
+
+    traduzirDeclaracaoComentario(comentario: Comentario): string {
+        let resultado = '';
+        if (comentario.multilinha) {
+            resultado += `/*`;
+            for (let linhaComentario of comentario.conteudo as string[]) {
+                resultado += `${linhaComentario}\n`;
+            }
+            resultado += `*/`;
+        } else {
+            resultado += `// ${comentario.conteudo as string}`;
+        }
+
+        return resultado;
+    }
+
+    traduzirConstrutoDefinirValor(definirValor: DefinirValor): string {
+        let resultado = '';
+        if (definirValor.objeto instanceof Isto) {
+            resultado = 'this.' + definirValor.nome.lexema + ' = ';
+        }
+
+        resultado += definirValor.valor.simbolo.lexema;
+        return resultado;
+    }
+
+    traduzirConstrutoDicionario(dicionario: Dicionario): string {
+        let resultado = '{';
+
+        for (let i = 0; i < dicionario.chaves.length; i++) {
+            resultado += this.dicionarioConstrutos[dicionario.chaves[i].constructor.name](dicionario.chaves[i]);
+            resultado += ':';
+            resultado += this.dicionarioConstrutos[dicionario.valores[i].constructor.name](dicionario.valores[i]) + ',';
+        }
+        resultado += '}';
+
+        return resultado;
+    }
+
+    traduzirConstrutoFimPara(fimPara: FimPara): string {
+        const traducaoIncremento = this.dicionarioDeclaracoes[fimPara.incremento.constructor.name](fimPara.incremento);
+        return traducaoIncremento;
+    }
+
+    traduzirConstrutoLiteral(literal: Literal): string {
+        if (typeof literal.valor === 'string') {
+            const possuiInterpolacao = /\$\{(verdadeiro|falso|nulo)\}/.test(literal.valor);
+
+            const valor = literal.valor.replace(/\$\{(verdadeiro|falso|nulo)\}/g, (_, match) => {
+                switch (match) {
+                    case 'verdadeiro':
+                        return '${true}';
+                    case 'falso':
+                        return '${false}';
+                    case 'nulo':
+                        return '${null}';
+                    default:
+                        return match;
+                }
+            });
+
+            return possuiInterpolacao ? `\`${valor}\`` : `"${literal.valor}"`;
+        }
+
+        return literal.valor;
+    }
+
+    traduzirConstrutoVariavel(variavel: Variavel, argumentos: Construto[]): string {
+        const argumentosResolvidos: string[] = [];
+        const argumentosValidados = argumentos || [];
+        for (const argumento of argumentosValidados) {
+            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
+            argumentosResolvidos.push(argumentoResolvido);
+        }
+
+        let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
+        textoArgumentos = textoArgumentos.slice(0, -2);
+
+        if (argumentosValidados.length > 0) {
+            return `${variavel.simbolo.lexema}(${textoArgumentos})`;
+        }
+        
+        return `${variavel.simbolo.lexema}`;
+    }
+
+    protected logicaComumBlocoEscopo(declaracoes: Declaracao[]): string {
+        let resultado = '{\n';
+        this.indentacao += 4;
+
+        if (typeof declaracoes[Symbol.iterator] === 'function') {
+            for (const declaracaoOuConstruto of declaracoes) {
+                resultado += ' '.repeat(this.indentacao);
+                const nomeConstrutor = declaracaoOuConstruto.constructor.name;
+                if (this.dicionarioConstrutos.hasOwnProperty(nomeConstrutor)) {
+                    resultado += this.dicionarioConstrutos[nomeConstrutor](declaracaoOuConstruto);
+                } else {
+                    resultado += this.dicionarioDeclaracoes[nomeConstrutor](declaracaoOuConstruto);
+                }
+
+                resultado += '\n';
+            }
+        }
+
+        this.indentacao -= 4;
+        resultado += ' '.repeat(this.indentacao) + '}\n';
+        return resultado;
+    }
+
+    traduzirDeclaracaoBloco(declaracaoBloco: Bloco): string {
+        return this.logicaComumBlocoEscopo(declaracaoBloco.declaracoes);
+    }
+
+    logicaTraducaoMetodoClasse(metodoClasse: FuncaoDeclaracao): string {
+        this.indentacao += 4;
+        let resultado = ' '.repeat(this.indentacao);
+        resultado += metodoClasse.simbolo.lexema === 'construtor' ? 'constructor(' : metodoClasse.simbolo.lexema + '(';
+
+        for (let parametro of metodoClasse.funcao.parametros) {
+            resultado += parametro.nome.lexema + ', ';
+        }
+        if (metodoClasse.funcao.parametros.length > 0) {
+            resultado = resultado.slice(0, -2);
+        }
+
+        resultado += ') ';
+        resultado += this.logicaComumBlocoEscopo(metodoClasse.funcao.corpo);
+        resultado += ' '.repeat(this.indentacao) + '\n';
+
+        this.indentacao -= 4;
+        return resultado;
+    }
+
+    traduzirDeclaracaoClasse(declaracaoClasse: Classe): string {
+        let resultado = 'export class ';
+
+        if (declaracaoClasse.superClasse)
+            resultado += `${declaracaoClasse.simbolo.lexema} extends ${declaracaoClasse.superClasse.simbolo.lexema} {\n`;
+        else resultado += declaracaoClasse.simbolo.lexema + ' {\n';
+
+        for (let metodo of declaracaoClasse.metodos) {
+            resultado += this.logicaTraducaoMetodoClasse(metodo);
+        }
+
+        resultado += '}';
+        return resultado;
+    }
+
+    traduzirDeclaracaoEnquanto(declaracaoEnquanto: Enquanto): string {
+        let resultado = 'enquanto (';
+        resultado +=
+            this.dicionarioConstrutos[declaracaoEnquanto.condicao.constructor.name](declaracaoEnquanto.condicao) + ') ';
+        resultado += this.dicionarioDeclaracoes[declaracaoEnquanto.corpo.constructor.name](declaracaoEnquanto.corpo);
+        return resultado;
+    }
+
+    traduzirDeclaracaoEscreva(declaracaoEscreva: Escreva): string {
+        let resultado = 'escreva(';
+        for (const argumento of declaracaoEscreva.argumentos) {
+            const valor = this.dicionarioConstrutos[argumento.constructor.name](argumento);
+            resultado += valor + ', ';
+        }
+
+        resultado = resultado.slice(0, -2);
+        resultado += ')';
+        return resultado;
+    }
+
+    traduzirDeclaracaoExpressao(declaracaoExpressao: Expressao): string {
+        return this.dicionarioConstrutos[declaracaoExpressao.expressao.constructor.name](declaracaoExpressao.expressao);
+    }
+
+    traduzirDeclaracaoFuncao(declaracaoFuncao: FuncaoDeclaracao): string {
+        let resultado = 'função ';
+        resultado += declaracaoFuncao.simbolo.lexema + '(';
+
+        for (const parametro of declaracaoFuncao.funcao.parametros) {
+            resultado += parametro.nome.lexema + ', ';
+        }
+
+        if (declaracaoFuncao.funcao.parametros.length > 0) {
+            resultado = resultado.slice(0, -2);
+        }
+
+        resultado += ') ';
+
+        resultado += this.logicaComumBlocoEscopo(declaracaoFuncao.funcao.corpo);
+        return resultado;
+    }
+
+    traduzirConstrutoLeia(declaracaoLeia: Leia) {
+        return `leia("${declaracaoLeia.argumentos[0].valor}")'`;
+    }
+
+    traduzirDeclaracaoParaCada(declaracaoParaCada: ParaCada): string {
+        let resultado = `para cada ${declaracaoParaCada.nomeVariavelIteracao} em `;
+        resultado +=
+            this.dicionarioConstrutos[declaracaoParaCada.vetor.constructor.name](declaracaoParaCada.vetor) + ' ';
+
+        resultado += this.dicionarioDeclaracoes[declaracaoParaCada.corpo.constructor.name](declaracaoParaCada.corpo);
+        return resultado;
+    }
+
+    traduzirDeclaracaoPara(declaracaoPara: Para): string {
+        let resultado = 'para ';
+        if (declaracaoPara.inicializador.constructor.name === 'Array') {
+            resultado +=
+                this.dicionarioDeclaracoes[declaracaoPara.inicializador[0].constructor.name](
+                    declaracaoPara.inicializador[0],
+                    false
+                ) + '; ';
+        } else {
+            resultado +=
+                this.dicionarioDeclaracoes[declaracaoPara.inicializador.constructor.name](
+                    declaracaoPara.inicializador,
+                    false
+                ) + '; ';
+        }
+
+        resultado +=
+            this.dicionarioConstrutos[declaracaoPara.condicao.constructor.name](declaracaoPara.condicao) + '; ';
+        resultado +=
+            this.dicionarioConstrutos[declaracaoPara.incrementar.constructor.name](declaracaoPara.incrementar) + ' ';
+
+        resultado += this.dicionarioDeclaracoes[declaracaoPara.corpo.constructor.name](declaracaoPara.corpo);
+        return resultado;
+    }
+
+    traduzirDeclaracaoRetorna(declaracaoRetorna: Retorna): string {
+        let resultado = 'retorna ';
+        const nomeConstrutor = declaracaoRetorna.valor.constructor.name;
+        return (resultado += this.dicionarioConstrutos[nomeConstrutor](declaracaoRetorna?.valor));
+    }
+
+    traduzirDeclaracaoSe(declaracaoSe: Se): string {
+        let resultado = 'se ';
+
+        const condicao = this.dicionarioConstrutos[declaracaoSe.condicao.constructor.name](declaracaoSe.condicao);
+
+        resultado += condicao;
+
+        resultado += ' ' + this.dicionarioDeclaracoes[declaracaoSe.caminhoEntao.constructor.name](declaracaoSe.caminhoEntao);
+
+        if (declaracaoSe.caminhoSenao !== null) {
+            resultado += ' '.repeat(this.indentacao);
+            resultado += ' senão ';
+
+            resultado += this.dicionarioDeclaracoes[declaracaoSe.caminhoSenao.constructor.name](
+                declaracaoSe.caminhoSenao
+            );
+        }
+
+        return resultado;
+    }
+
+    traduzirDeclaracaoTente(declaracaoTente: Tente): string {
+        let resultado = 'try {\n';
+        this.indentacao += 4;
+        resultado += ' '.repeat(this.indentacao);
+
+        for (let condicao of declaracaoTente.caminhoTente) {
+            resultado += this.dicionarioDeclaracoes[condicao.constructor.name](condicao) + '\n';
+            resultado += ' '.repeat(this.indentacao);
+        }
+        resultado += '}';
+
+        if (declaracaoTente.caminhoPegue !== null) {
+            resultado += '\ncatch {\n';
+            resultado += ' '.repeat(this.indentacao);
+            if (Array.isArray(declaracaoTente.caminhoPegue)) {
+                for (let declaracao of declaracaoTente.caminhoPegue) {
+                    resultado += this.dicionarioDeclaracoes[declaracao.constructor.name](declaracao) + '\n';
+                }
+            } else {
+                for (let corpo of declaracaoTente.caminhoPegue.corpo) {
+                    resultado += this.dicionarioDeclaracoes[corpo.constructor.name](corpo) + '\n';
+                }
+            }
+
+            resultado += ' '.repeat(this.indentacao);
+            resultado += '}';
+        }
+        if (declaracaoTente.caminhoFinalmente !== null) {
+            resultado += '\nfinally {\n';
+            for (let finalmente of declaracaoTente.caminhoFinalmente) {
+                resultado += this.dicionarioDeclaracoes[finalmente.constructor.name](finalmente) + '\n';
+            }
+            resultado += ' '.repeat(this.indentacao);
+            resultado += '}';
+        }
+
+        return resultado;
+    }
+
+    traduzirDeclaracaoConst(declaracaoConst: Const): string {
+        let resultado = 'const ';
+        resultado += declaracaoConst.simbolo.lexema;
+        if (!declaracaoConst?.inicializador) resultado += ';';
+        else {
+            resultado += ' = ';
+            if (this.dicionarioConstrutos[declaracaoConst.inicializador.constructor.name]) {
+                resultado += this.dicionarioConstrutos[declaracaoConst.inicializador.constructor.name](
+                    declaracaoConst.inicializador
+                );
+            } else {
+                resultado += this.dicionarioDeclaracoes[declaracaoConst.inicializador.constructor.name](
+                    declaracaoConst.inicializador
+                );
+            }
+            resultado += ';';
+        }
+        return resultado;
+    }
+
+    traduzirDeclaracaoVar(declaracaoVar: Var, adicionarPontoEVirgula: boolean = true): string {
+        let resultado = 'var ';
+        resultado += declaracaoVar.simbolo.lexema;
+        if (!declaracaoVar?.inicializador && adicionarPontoEVirgula) resultado += ';';
+        else {
+            resultado += ' = ';
+            if (this.dicionarioConstrutos[declaracaoVar.inicializador.constructor.name]) {
+                resultado += this.dicionarioConstrutos[declaracaoVar.inicializador.constructor.name](
+                    declaracaoVar.inicializador
+                );
+            } else {
+                resultado += this.dicionarioDeclaracoes[declaracaoVar.inicializador.constructor.name](
+                    declaracaoVar.inicializador
+                );
+            }
+            // if (adicionarPontoEVirgula) resultado += ';';
+        }
+
+        return resultado;
+    }
+
+    // TODO: Talvez terminar (ou remover, sei lá).
+    traduzirFuncaoAnonimaParaLambda(argumento: Construto): string {
+        return '';
+    }
+
+    traduzirConstrutoAcessoMetodo(acessoMetodo: AcessoMetodo, argumentos: Construto[]): string {
+        switch (acessoMetodo.objeto.constructor.name) {
+            case 'Variavel':
+                let objetoVariavel = acessoMetodo.objeto as Variavel;
+                return this.traduzirFuncaoOuMetodo(acessoMetodo.nomeMetodo, objetoVariavel.simbolo.lexema, argumentos);
+            default:
+                const objetoResolvido = this.dicionarioConstrutos[acessoMetodo.objeto.constructor.name](
+                    acessoMetodo.objeto
+                );
+                return `${objetoResolvido}.${acessoMetodo.nomeMetodo}`;
+        }
+    }
+
+    traduzirConstrutoAcessoMetodoOuPropriedade(
+        acessoMetodo: AcessoMetodoOuPropriedade,
+        argumentos: Construto[]
+    ): string {
+        if (acessoMetodo.objeto instanceof Variavel) {
+            let objetoVariavel = acessoMetodo.objeto as Variavel;
+            return `${this.traduzirFuncaoOuMetodo(acessoMetodo.simbolo.lexema, objetoVariavel.simbolo.lexema, argumentos)}`;
+        }
+
+        return `this.${acessoMetodo.simbolo.lexema}`;
+    }
+
+    traduzirFuncaoConstruto(funcaoConstruto: FuncaoConstruto): string {
+        let resultado = 'função(';
+        for (const parametro of funcaoConstruto.parametros) {
+            resultado += parametro.nome.lexema + ', ';
+        }
+
+        if (funcaoConstruto.parametros.length > 0) {
+            resultado = resultado.slice(0, -2);
+        }
+
+        resultado += ') ';
+
+        resultado += this.logicaComumBlocoEscopo(funcaoConstruto.corpo);
+        return resultado;
+    }
+
+    traduzirConstrutoLogico(logico: Logico): string {
+        let direita = this.dicionarioConstrutos[logico.direita.constructor.name](logico.direita);
+        let operador = this.traduzirSimboloOperador(logico.operador);
+        let esquerda = this.dicionarioConstrutos[logico.esquerda.constructor.name](logico.esquerda);
+
+        return `${direita} ${operador} ${esquerda}`;
+    }
+
+    // TODO: Eliminar o soft cast para `any`.
+    traduzirConstrutoAtribuicaoPorIndice(AtribuicaoPorIndice: AtribuicaoPorIndice): string {
+        let resultado = '';
+
+        resultado += (AtribuicaoPorIndice.objeto as any).simbolo.lexema + '[';
+        resultado +=
+            this.dicionarioConstrutos[AtribuicaoPorIndice.indice.constructor.name](AtribuicaoPorIndice.indice) + ']';
+        resultado += ' = ';
+
+        if ((AtribuicaoPorIndice?.valor as any)?.simbolo?.lexema) {
+            resultado += `${(AtribuicaoPorIndice.valor as any).simbolo.lexema}`;
+        } else {
+            resultado += this.dicionarioConstrutos[AtribuicaoPorIndice.valor.constructor.name](
+                AtribuicaoPorIndice.valor
+            );
+        }
+
+        return resultado;
+    }
+
+    traduzirConstrutoAcessoIndiceVariavel(acessoIndiceVariavel: AcessoIndiceVariavel): string {
+        let resultado = '';
+
+        resultado += this.dicionarioConstrutos[acessoIndiceVariavel.entidadeChamada.constructor.name](
+            acessoIndiceVariavel.entidadeChamada
+        );
+        resultado += `[${this.dicionarioConstrutos[acessoIndiceVariavel.indice.constructor.name](
+            acessoIndiceVariavel.indice
+        )}]`;
+
+        return resultado;
+    }
+
+    traduzirConstrutoArgumentoReferenciaFuncao(
+        argumentoReferenciaFuncao: ArgumentoReferenciaFuncao,
+        argumentos: Construto[]
+    ): string {
+        const argumentosResolvidos: string[] = [];
+        for (const argumento of argumentos) {
+            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
+            argumentosResolvidos.push(argumentoResolvido);
+        }
+
+        let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
+        textoArgumentos = textoArgumentos.slice(0, -2);
+
+        return `${argumentoReferenciaFuncao.simboloFuncao.lexema}(${textoArgumentos})`;
+    }
+
+    traduzirConstrutoReferenciaFuncao(referenciaFuncao: ReferenciaFuncao, argumentos: Construto[]): string {
+        const argumentosResolvidos: string[] = [];
+        for (const argumento of argumentos) {
+            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
+            argumentosResolvidos.push(argumentoResolvido);
+        }
+
+        let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
+        textoArgumentos = textoArgumentos.slice(0, -2);
+
+        return `${referenciaFuncao.simboloFuncao.lexema}(${textoArgumentos})`;
+    }
+
+    traduzirConstrutoTipoDe(tipoDe: TipoDe): string {
+        let resultado = 'typeof ';
+
+        if (!tipoDe.valor)
+            resultado += tipoDe.valor; // Qual o sentido disso?
+        else if (typeof tipoDe.valor === 'string') resultado += `'${tipoDe.valor}'`;
+        else if (typeof tipoDe.valor === 'number') resultado += tipoDe.valor;
+        else {
+            // Talvez isso seja uma péssima ideia.
+            // Pensar em algo melhor.
+            let alvoTipoDe = String(this.dicionarioConstrutos[tipoDe.valor.constructor.name](tipoDe.valor));
+            if (alvoTipoDe.startsWith('new')) {
+                alvoTipoDe = alvoTipoDe.slice(4, -2);
+            }
+
+            resultado += `${alvoTipoDe}`;
+        }
+
+        return resultado;
+    }
+
+    traduzirConstrutoVetor(vetor: Vetor): string {
+        if (!vetor.valores.length) {
+            return '[]';
+        }
+
+        let resultado = '[';
+
+        for (let valor of vetor.valores) {
+            resultado += `${this.dicionarioConstrutos[valor.constructor.name](valor)}, `;
+        }
+        if (vetor.valores.length > 0) {
+            resultado = resultado.slice(0, -2);
+        }
+
+        resultado += ']';
+
+        return resultado;
+    }
+
+    traduzirConstrutoUnario(unario: Unario): string {
+        let resultado = '';
+        if ([tiposDeSimbolos.INCREMENTAR, tiposDeSimbolos.DECREMENTAR].includes(unario.operador.tipo)) {
+            resultado += unario.operando.valor ?? unario.operando.simbolo.lexema;
+            resultado += unario.operador.tipo === tiposDeSimbolos.INCREMENTAR ? '++' : '--';
+        } else {
+            resultado += this.traduzirSimboloOperador(unario.operador);
+            resultado += unario.operando.valor ?? unario.operando.simbolo.lexema;
+        }
+        return resultado;
+    }
+
+    dicionarioConstrutos = {
+        AcessoIndiceVariavel: this.traduzirConstrutoAcessoIndiceVariavel.bind(this),
+        AcessoMetodo: this.traduzirConstrutoAcessoMetodo.bind(this),
+        AcessoMetodoOuPropriedade: this.traduzirConstrutoAcessoMetodoOuPropriedade.bind(this),
+        Agrupamento: this.traduzirConstrutoAgrupamento.bind(this),
+        ArgumentoReferenciaFuncao: this.traduzirConstrutoArgumentoReferenciaFuncao.bind(this),
+        AtribuicaoPorIndice: this.traduzirConstrutoAtribuicaoPorIndice.bind(this),
+        Atribuir: this.traduzirConstrutoAtribuir.bind(this),
+        Binario: this.traduzirConstrutoBinario.bind(this),
+        Chamada: this.traduzirConstrutoChamada.bind(this),
+        DefinirValor: this.traduzirConstrutoDefinirValor.bind(this),
+        Dicionario: this.traduzirConstrutoDicionario.bind(this),
+        FimPara: this.traduzirConstrutoFimPara.bind(this),
+        FuncaoConstruto: this.traduzirFuncaoConstruto.bind(this),
+        Isto: () => 'this',
+        Leia: this.traduzirConstrutoLeia.bind(this),
+        Literal: this.traduzirConstrutoLiteral.bind(this),
+        Logico: this.traduzirConstrutoLogico.bind(this),
+        ReferenciaFuncao: this.traduzirConstrutoReferenciaFuncao.bind(this),
+        TipoDe: this.traduzirConstrutoTipoDe.bind(this),
+        Unario: this.traduzirConstrutoUnario.bind(this),
+        Variavel: this.traduzirConstrutoVariavel.bind(this),
+        Vetor: this.traduzirConstrutoVetor.bind(this),
+    };
+
+    dicionarioDeclaracoes = {
+        Bloco: this.traduzirDeclaracaoBloco.bind(this),
+        Classe: this.traduzirDeclaracaoClasse.bind(this),
+        Const: this.traduzirDeclaracaoConst.bind(this),
+        Comentario: this.traduzirDeclaracaoComentario.bind(this),
+        Continua: () => 'continue',
+        Enquanto: this.traduzirDeclaracaoEnquanto.bind(this),
+        Escreva: this.traduzirDeclaracaoEscreva.bind(this),
+        Expressao: this.traduzirDeclaracaoExpressao.bind(this),
+        FuncaoDeclaracao: this.traduzirDeclaracaoFuncao.bind(this),
+        Para: this.traduzirDeclaracaoPara.bind(this),
+        ParaCada: this.traduzirDeclaracaoParaCada.bind(this),
+        Retorna: this.traduzirDeclaracaoRetorna.bind(this),
+        Se: this.traduzirDeclaracaoSe.bind(this),
+        Sustar: () => 'break',
+        Tente: this.traduzirDeclaracaoTente.bind(this),
+        Var: this.traduzirDeclaracaoVar.bind(this),
+    };
+
+    traduzir(declaracoes: Declaracao[]): string {
+        let resultado = '';
+
+        for (const declaracao of declaracoes) {
+            resultado += `${this.dicionarioDeclaracoes[declaracao.constructor.name](declaracao)} \n`;
+        }
+
+        return resultado;
+    }
+}


Test patch:
diff --git a/testes/tradutores/tradutor-reverso-tenda.test.ts b/testes/tradutores/tradutor-reverso-tenda.test.ts
new file mode 100644
index 00000000..49e81b71
--- /dev/null
+++ b/testes/tradutores/tradutor-reverso-tenda.test.ts
@@ -0,0 +1,277 @@
+import { TradutorReversoTenda } from '../../fontes/tradutores/tradutor-reverso-tenda';
+import { LexadorTenda } from '../../fontes/lexador';
+import { AvaliadorSintaticoTenda } from '../../fontes/avaliador-sintatico';
+
+describe('Tradutor Tenda -> Delégua', () => {
+    let lexador: LexadorTenda;
+    let avaliadorSintatico: AvaliadorSintaticoTenda;
+    const tradutor: TradutorReversoTenda = new TradutorReversoTenda();
+
+    beforeEach(() => {
+        lexador = new LexadorTenda();
+        avaliadorSintatico = new AvaliadorSintaticoTenda();
+    });
+
+    it('exiba -> escreva', () => {
+        const codigo = `exiba("Oi")`;
+
+        const retornoLexador = lexador.mapear(codigo.split('\n'), -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/escreva\("Oi"\)/i);
+    });
+
+    it('dicionário', () => {
+        const codigo = [
+            'seja dicionário = { "nome": "Tenda", "versão": 1.0 }',
+            'seja nome = dicionário["nome"]',
+            'seja versão = dicionário.versão',
+            'exiba("Nome: " + nome + ", Versão: " + versão)',
+        ];
+
+        const retornoLexador = lexador.mapear(codigo, -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var dicionário = {"nome":"Tenda","versão":1,}/i);
+        expect(resultado).toMatch(/var nome = dicionário\["nome"\]/i);
+        expect(resultado).toMatch(/var versão = dicionário.versão/i);
+        expect(resultado).toMatch(/escreva\("Nome: " \+ nome \+ ", Versão: " \+ versão\)/i);
+    });
+
+    it('enquanto', () => {
+        const codigo = [
+            'seja contador = 1',
+            'enquanto contador <= 5 faça',
+            '    exiba("Contador: " + contador)',
+            '    contador = contador + 1',
+            'fim'
+        ];
+
+        const retornoLexador = lexador.mapear(codigo, -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var contador = 1/i);
+        expect(resultado).toMatch(/enquanto \(contador <= 5\) {/i);
+        expect(resultado).toMatch(/escreva\("Contador: " \+ contador\)/i);
+        expect(resultado).toMatch(/contador = contador \+ 1/i);
+        expect(resultado).toMatch(/}/i);
+    });
+
+    describe('Funções', () => {
+        it('Função implícita, com parênteses e retorno na mesma linha', () => {
+            const codigo = [
+                'seja soma(a, b) = a + b'
+            ];
+
+            const retornoLexador = lexador.mapear(codigo, -1);
+            const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+            const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+            expect(resultado).toBeTruthy();
+            expect(resultado).toMatch(/função soma\(a, b\) \{/i);
+            expect(resultado).toMatch(/retorna a \+ b/i);
+        });
+
+        it('Função estruturada, com bloco', () => {
+            const codigo = [
+                'seja soma(lista) =',
+                '  faça',
+                '    seja total = 0',
+                '    para cada i em lista faça',
+                '      total = total + i',
+                '    fim',
+                '    retorna total',
+                '  fim',
+                'exiba(soma([1, 3, 5, 7, 9]))'
+            ];
+
+            const retornoLexador = lexador.mapear(codigo, -1);
+            const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+            const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+            expect(resultado).toBeTruthy();
+            expect(resultado).toMatch(/função soma\(lista\) \{/i);
+            expect(resultado).toMatch(/var total = 0/i);
+            expect(resultado).toMatch(/para cada i em lista {/i);
+            expect(resultado).toMatch(/total = total \+ i/i);
+            expect(resultado).toMatch(/retorna total/i);
+            expect(resultado).toMatch(/escreva\(soma\(\[1, 3, 5, 7, 9\]\)\)/i);
+        });
+
+        it('Função anônima, usando palavra reservada `função`', () => {
+            const codigo = [
+                'seja soma = função(a, b) -> a + b',
+                'seja resultado = soma(10, 5)',
+                'exiba("A soma é: " + resultado)'
+            ];
+
+            const retornoLexador = lexador.mapear(codigo, -1);
+            const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+            const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+            expect(resultado).toBeTruthy();
+            expect(resultado).toMatch(/var soma = função\(a, b\) \{/i);
+            expect(resultado).toMatch(/retorna a \+ b/i);
+            expect(resultado).toMatch(/escreva\("A soma é: " \+ resultado\)/i);
+        });
+    });
+
+    it('leia -> leia', () => {
+        const codigo = `leia("Digite sua idade: ")`;
+
+        const retornoLexador = lexador.mapear(codigo.split('\n'), -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/leia\(\"Digite sua idade: \"\)/i);
+    });
+
+    it('operações de comparação', () => {
+        const codigo = [
+            'seja a = 10',
+            'seja b = 5',
+            'seja maior = a > b',
+            'seja menor = a < b',
+            'seja maior_ou_igual = a >= b',
+            'seja menor_ou_igual = a <= b',
+            'seja igual = a é b',
+            'seja diferente = a não é b',
+            'seja negado = não a',
+        ];
+        
+        const retornoLexador = lexador.mapear(codigo, -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var a = 10/i);
+        expect(resultado).toMatch(/var b = 5/i);
+        expect(resultado).toMatch(/var maior = a > b/i);
+        expect(resultado).toMatch(/var menor = a < b/i);
+        expect(resultado).toMatch(/var maior_ou_igual = a >= b/i);
+        expect(resultado).toMatch(/var menor_ou_igual = a <= b/i);
+        expect(resultado).toMatch(/var igual = a == b/i);
+        expect(resultado).toMatch(/var diferente = a != b/i);
+        expect(resultado).toMatch(/var negado = !a/i);
+    });
+
+    it('operações de concatenação', () => {
+        const codigo = [
+            'seja texto1 = "Olá"',
+            'seja texto2 = "Mundo"',
+            'seja texto_concatenado = texto1 + " " + texto2',
+            'seja lista1 = [1, 2, 3]',
+            'seja lista2 = [4, 5, 6]',
+            'seja lista_concatenada = lista1 + lista2'
+        ];
+        
+        const retornoLexador = lexador.mapear(codigo, -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var texto1 = \"Olá\"/i);
+        expect(resultado).toMatch(/var texto2 = \"Mundo\"/i);
+        expect(resultado).toMatch(/var texto_concatenado = texto1 \+ \" \" \+ texto2/i);
+        expect(resultado).toMatch(/var lista1 = \[1, 2, 3\]/i);
+        expect(resultado).toMatch(/var lista2 = \[4, 5, 6\]/i);
+        expect(resultado).toMatch(/var lista_concatenada = lista1 \+ lista2/i);
+    });
+
+    it('operações matemáticas', () => {
+        const codigo = [
+            "seja a = 10",
+            "seja b = 5",
+            "seja soma = a + b",
+            "seja subtração = a - b",
+            "seja multiplicação = a * b",
+            "seja divisão = a / b",
+            "seja resto = a % b",
+            "seja potência = a ^ b",
+            "seja negativo = -a",
+        ];
+        
+        const retornoLexador = lexador.mapear(codigo, -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var a = 10/i);
+        expect(resultado).toMatch(/var b = 5/i);
+        expect(resultado).toMatch(/var soma = a \+ b/i);
+        expect(resultado).toMatch(/var subtração = a - b/i);
+        expect(resultado).toMatch(/var multiplicação = a \* b/i);
+        expect(resultado).toMatch(/var divisão = a \/ b/i);
+        expect(resultado).toMatch(/var resto = a % b/i);
+        expect(resultado).toMatch(/var potência = a \^ b/i);
+        expect(resultado).toMatch(/var negativo = -a/i);
+    });
+
+    it('seja -> var', () => {
+        const codigo = `seja nome = "Tenda"
+        seja idade = 10
+        seja lista = [1, 2, 3, 4, 5]
+        `;
+
+        const retornoLexador = lexador.mapear(codigo.split('\n'), -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var nome = \"Tenda\"/i);
+        expect(resultado).toMatch(/var idade = 10/i);
+        expect(resultado).toMatch(/var lista = \[1, 2, 3, 4, 5\]/i);
+    });
+
+    it('para cada, iterando variável de controle', () => {
+        const codigo = [
+            "seja total = 0",
+            "para cada i em 1 até 10 faça",
+            "    total = total + i",
+            "fim",
+            "exiba(total)",
+        ];
+        const retornoLexador = lexador.mapear(codigo, -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var total = 0/i);
+        expect(resultado).toMatch(/para i = 1; i <= 10; i = i \+ 1 {/i);
+        expect(resultado).toMatch(/total = total \+ i/i);
+        expect(resultado).toMatch(/escreva\(total\)/i);
+    });
+
+    it('para cada, iterando lista de elementos', () => {
+        const codigo = [
+            'seja total = 0',
+            'para cada i em [1, 2, 3, 4, 5] faça',
+            '    total = total + i',
+            'fim',
+            'exiba(total)'
+        ];
+        const retornoLexador = lexador.mapear(codigo, -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var total = 0/i);
+        expect(resultado).toMatch(/para cada i em \[1, 2, 3, 4, 5\] \{/i);
+        expect(resultado).toMatch(/total = total \+ i/i);
+        expect(resultado).toMatch(/escreva\(total\)/i);
+    });
+
+    it('se senão', () => {
+        const codigo = `seja idade = 18
+        se idade >= 18 então
+            exiba("Você é maior de idade.")
+        senão
+            exiba("Você é menor de idade.")
+        fim
+        `;
+
+        const retornoLexador = lexador.mapear(codigo.split('\n'), -1);
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/var idade = 18/i);
+        expect(resultado).toMatch(/se idade >= 18/i);
+        expect(resultado).toMatch(/escreva\(\"Você é maior de idade.\"\)/i);
+        expect(resultado).toMatch(/senão/i);
+        expect(resultado).toMatch(/escreva\(\"Você é menor de idade.\"\)/i);
+    });
+});