Projeto Integrador: Gramática Formal da Linguagem Didágica 📝
🎯 Desenvolvimento da Gramática para o Compilador Didágica
A linguagem Didágica apresenta desafios únicos: sintaxe em português, convenções de nomenclatura rígidas (CamelCase para palavras-chave, snake_case para identificadores), sistema de mutabilidade explícita, e integração de conceitos de engenharia de software diretamente na sintaxe.
📋 Gramática Formal Desenvolvida
Definição Completa G = (V, T, P, S)
Desenvolvi a gramática formal completa para a Didágica seguindo rigorosamente a teoria estudada:
Conjunto de Variáveis (V):
V = {Programa, BlocoDeclarações, Declaração, DeclaraçãoVariável,
DeclaraçãoFuncao, DeclaraçãoClasse, DeclaraçãoContrato,
BlocoComandos, Comando, ComandoCondicional, ComandoLaço,
ComandoAtribuição, ComandoEscrita, Expressão, ExpressãoLógica,
ExpressãoRelacional, ExpressãoAritmética, Termo, Fator,
ListaParametros, ListaArgumentos, Tipo}
Conjunto de Terminais (T):
T = {Guarde, como, mutável, imutável, Escreva, Se, então, Senão, Fim,
Enquanto, ParaCada, de, até, Repita, AtéQue, Função, retorne,
Classe, herda, Construtor, Método, propriedade, Contrato, componente,
Inteiro, Real, Texto, Booleano, Nulo, E, Ou, Não,
==, !=, >, <, >=, <=, +, -, *, /, =,
(, ), {, }, ",", ;, identificador, literal_inteiro, literal_real,
literal_texto, literal_booleano, leia_entrada, para_inteiro,
para_real, para_texto, para_booleano}
Símbolo Inicial: S = Programa
Principais Regras de Produção Implementadas
🔧 Regras Fundamentais da Linguagem
- Programa \rightarrow BlocoDeclarações BlocoComandosPrincipal
- BlocoDeclarações \rightarrow Declaração BlocoDeclarações | \varepsilon
- Declaração \rightarrow DeclaraçãoVariável | DeclaraçãoFuncao | DeclaraçãoClasse
- DeclaraçãoVariável \rightarrow Guarde Tipo literal como identificador | Guarde mutável Tipo literal como identificador
- Tipo \rightarrow Inteiro | Real | Texto | Booleano
- DeclaraçãoFuncao \rightarrow Funcao Tipo identificador ( ListaParametros ) BlocoComandos Fim
- DeclaraçãoClasse \rightarrow Classe identificador BlocoClasse Fim | Classe identificador herda identificador BlocoClasse Fim
- BlocoComandos \rightarrow Comando BlocoComandos | \varepsilon
- Comando \rightarrow ComandoAtribuição | ComandoCondicional | ComandoLaço | ComandoEscrita
- BlocoComandosPrincipal \rightarrow Comando BlocoComandosPrincipal | \varepsilon
- ComandoCondicional \rightarrow Se Expressão então BlocoComandos Fim | Se Expressão então BlocoComandos Senão BlocoComandos Fim
- ComandoLaço \rightarrow Enquanto Expressão BlocoComandos Fim | ParaCada Tipo identificador de literal até literal BlocoComandos Fim
- ComandoEscrita \rightarrow Escreva ListaArgumentos
- Expressão \rightarrow ExpressãoLógica
- ExpressãoLógica \rightarrow ExpressãoRelacional | ExpressãoLógica E ExpressãoRelacional | ExpressãoLógica Ou ExpressãoRelacional | Não ExpressãoLógica
- ExpressãoRelacional \rightarrow ExpressãoAritmética | ExpressãoAritmética == ExpressãoAritmética | ExpressãoAritmética != ExpressãoAritmética | ExpressãoAritmética > ExpressãoAritmética | ExpressãoAritmética < ExpressãoAritmética | ExpressãoAritmética >= ExpressãoAritmética | ExpressãoAritmética <= ExpressãoAritmética
- ExpressãoAritmética \rightarrow Termo | ExpressãoAritmética + Termo | ExpressãoAritmética - Termo
- Termo \rightarrow Fator | Termo * Fator | Termo / Fator
- Fator \rightarrow identificador | literal_inteiro | literal_real | literal_texto | literal_booleano | ( Expressão ) | identificador ( ListaArgumentos )
🏗️ Classificação na Hierarquia de Chomsky
📊 Análise Formal da Classificação
Analisei rigorosamente minha gramática e classifiquei-a como Tipo 2 (Livre de Contexto) na hierarquia de Chomsky:
Justificativa:
- Todas as produções têm a forma A → α (lado esquerdo com apenas um não-terminal)
- Não há dependências contextuais nas regras
- A gramática gera linguagem que não é regular (devido a estruturas aninhadas)
- Mas é reconhecível por autômato de pilha
Verificação:
- ✅ Não é Tipo 3 (Regular): estruturas como
Se...Fimaninhadas não são regulares - ✅ É Tipo 2 (Livre de Contexto): todas as regras seguem formato A → α
- ❌ Não precisa ser Tipo 1 (Sensível ao Contexto): não há regras αAβ → αγβ
- ❌ Não precisa ser Tipo 0 (Irrestrita): gramática é bem estruturada
🔍 Limitações da Gramática e Análise Semântica
A gramática livre de contexto que desenvolvi, embora poderosa para a análise sintática, possui uma limitação inerente: ela não é capaz de verificar restrições que dependem do contexto em que um símbolo é utilizado.
A regra fundamental de que uma variável deve ser declarada antes de ser usada é um exemplo clássico dessa limitação. A gramática, por si só, só consegue verificar se a estrutura de um comando de atribuição (ComandoAtribuição -> identificador = Expressão) é válida, mas não consegue “lembrar” se o identificador já foi visto em uma DeclaraçãoVariável em um ponto anterior do código.
Para resolver essa questão, a verificação é delegada a uma fase posterior do compilador, a Análise Semântica. Nesta etapa, o compilador percorre a Árvore de Sintaxe Abstrata (AST) construída pelo parser e utiliza uma tabela de símbolos para rastrear todas as variáveis declaradas. Somente após a declaração, o uso de um identificador é considerado válido.
Essa separação de tarefas é uma decisão de design que equilibra a expressividade da linguagem com a eficiência do compilador, permitindo que a análise sintática seja realizada com os algoritmos eficientes das linguagens livres de contexto, enquanto restrições mais complexas são tratadas de forma sistemática em uma etapa separada.
🔍 Resolução de Ambiguidades
Problemas Identificados e Soluções
⚠️ Ambiguidades Tratadas
1. Problema do Dangling-Else:
Solução: Regra de associação - Senão sempre se associa ao Se mais próximo não pareado.
2. Precedência de Operadores:
Estabeleci hierarquia clara: 1. () - Parênteses 2. Não - Negação lógica 3. * / - Multiplicação e divisão 4. + - - Adição e subtração 5. == != > < >= <= - Comparações 6. E - AND lógico 7. Ou - OR lógico
3. Associatividade:
- Operadores aritméticos: associativos à esquerda
- Operadores lógicos: associativos à esquerda
- Comparações: não associativas (erro se encadeadas)
🧪 Exemplos de Derivação
Programa Simples com Estrutura Condicional
🔬 Derivação Completa
Programa:
Derivação:
Programa
⇒ BlocoDeclarações
⇒ Declaração BlocoDeclarações
⇒ DeclaraçãoVariável BlocoDeclarações
⇒ Guarde Tipo literal como identificador BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Declaração BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Comando BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima ComandoCondicional BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se Expressão então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se ExpressãoLógica então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se ExpressãoRelacional então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se ExpressãoAritmética >= ExpressãoAritmética então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se Termo >= ExpressãoAritmética então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se Fator >= ExpressãoAritmética então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= ExpressãoAritmética então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= Termo então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= Fator então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então Comando BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então ComandoEscrita BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então Escreva ListaArgumentos BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então Escreva literal_texto BlocoComandos Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então Escreva literal_texto ε Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então Escreva literal_texto Fim BlocoDeclarações
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então Escreva literal_texto Fim ε
⇒ Guarde Inteiro 18 como idade_minima Se identificador >= literal_inteiro então Escreva literal_texto Fim
Programa com Função
🔧 Exemplo de Estrutura Mais Complexa
Programa:
Funcao Inteiro somar(Inteiro a, Inteiro b)
retorne a + b
Fim
Guarde Inteiro somar(5, 3) como resultado
Escreva "Resultado:", resultadoÁrvore de Derivação (parcial):
Programa
├── BlocoDeclarações
│ ├── DeclaraçãoFuncao
│ │ └── Funcao Inteiro somar(...) Fim
│ └── BlocoDeclarações
│ ├── DeclaraçãoVariável
│ │ └── Guarde Inteiro somar(5, 3) como resultado
│ └── BlocoDeclarações
│ └── ε (A declaração da variável seria o último BlocoDeclarações)
└── BlocoComandosPrincipal (?)
└── ComandoEscrita
└── Escreva "Resultado:", resultado
🎯 Características Específicas da Didágica
Elementos Únicos Implementados
🌟 Funcionalidades Educacionais
1. Sintaxe Natural em Português:
Guarde Inteiro 25 como minha_idadeem vez deint minha_idade = 25Se...então...Senão...Fimem vez deif...elseEnquanto...Fimem vez dewhile
2. Sistema de Mutabilidade Explícita:
Guarde Inteiro 10 como constante # imutável por padrão
Guarde mutável Inteiro 20 como Variável # explicitamente mutável
3. Convenções de Nomenclatura Enforçadas:
- Palavras Reservadas: CamelCase (Guarde, Escreva, Funcao)
- Identificadores: snake_case obrigatório (minha_Variável, idade_usuario)
4. Estruturas Verbosas mas Claras:
ParaCada Inteiro i de 1 até 10
Escreva "Número:", i
Fim
5. Funções Nativas Educacionais:
leia_entrada()- entrada do usuáriopara_inteiro(),para_real(),para_texto()- conversões explícitas
📊 Validação e Testes
Programas de Teste Criados
🧪 Suite de Testes Desenvolvida
Teste 1 - Programa Básico:
Escreva "Olá, mundo!"
Guarde Texto "Didágica" como nome_linguagem
Escreva "Linguagem:", nome_linguagem✅ Status: Deriva corretamente
Teste 2 - Estruturas de Controle:
Guarde Inteiro 10 como limite
ParaCada Inteiro i de 1 até limite
Se i == 5 então
Escreva "Meio do caminho"
Senão
Escreva "Número:", i
Fim
Fim✅ Status: Deriva corretamente, sem ambiguidades
Teste 3 - Função com Parâmetros:
Funcao Real calcular_media(Real a, Real b)
retorne (a + b) / 2.0
Fim
Guarde Real calcular_media(8.5, 9.2) como media
Escreva "Média:", media✅ Status: Deriva corretamente
Teste 4 - Classe com Herança:
Classe Pessoa
propriedade Texto nome
propriedade Inteiro idade
Fim
Classe Aluno herda Pessoa
propriedade Texto matricula
Metodo mostrar_info()
Escreva "Aluno:", eu.nome
Fim
Fim✅ Status: Deriva corretamente
Análise de Erros Sintáticos
⚠️ Casos de Erro Testados
Erro 1 - Convenção de Nomenclatura:
❌ Resultado: Rejeitado pela gramática (correto)
Erro 2 - Estrutura Incompleta:
❌ Resultado: Rejeitado pela gramática (correto)
Erro 3 - Operador Inexistente:
❌ Resultado: Rejeitado pela gramática (correto)
🔄 Preparação para Próxima Semana
🚀 Interface com Linguagens Regulares
A gramática que desenvolvi esta semana estabelece o contexto completo para a próxima fase: especificação dos tokens como linguagens regulares.
Tokens que precisam ser especificados com expressões regulares:
identificador: [a-z][a-z0-9_]* (snake_case obrigatório)literal_inteiro: [0-9]+literal_real: [0-9]+.[0-9]+literal_texto: “[^"]*”- Palavras Reservadas: strings exatas (Guarde, Escreva, Se, etc.)
Desafios identificados para próxima semana:
- Implementar reconhecimento de snake_case vs CamelCase
- Distinguir palavras-chave de identificadores
- Tratar caracteres acentuados em strings
- Implementar funções nativas (leia_entrada, para_inteiro, etc.)
A gramática não-ambígua que construí garante que posso implementar parser eficiente usando algoritmos LL(1) ou LR(1).
💭 Reflexões sobre o Desenvolvimento
🤔 Lições Aprendidas
Desafios Enfrentados:
- Balancear naturalidade e formalismo: Manter sintaxe próxima ao português sem comprometer precisão formal
- Eliminar ambiguidades: Especialmente com operadores lógicos em português (E, Ou, Não)
- Enforçar convenções: Garantir que gramática rejeite identificadores que não seguem snake_case
Decisões Importantes:
- Verbosidade educacional: Preferi clareza sobre concisão (ParaCada…de…até vs for)
- Mutabilidade explícita: Forçar programador a decidir conscientemente sobre mutabilidade
- Operadores híbridos: Misturar símbolos matémáticos com palavras portuguesas
Próximos Passos:
- Implementar analisador léxico baseado nos tokens definidos
- Testar gramática com parser recursivo descendente
- Desenvolver mensagens de erro educacionalmente úteis
- Preparar exemplos progressivos para demonstrar capacidades da linguagem