Plano de Aulas
Fluxo de Aprendizagem e Integração com o Projeto Integrador
Este documento é o plano global da disciplina: para cada módulo de conteúdo, ele fixa objetivos, competências, habilidades, conteúdo a apresentar, tarefas do Projeto Integrador e as estratégias de condução. É a fonte de escopo que os demais documentos da disciplina seguem, e por isso qualquer alteração aqui se propaga a todo o material do módulo correspondente.
O ciclo de cada módulo tem duas metades com funções distintas e não intercambiáveis. A metade teórica apresenta o conteúdo e conduz, ao vivo, a construção da implementação de referência; a metade de tutoria é o espaço em que cada grupo faz o próprio artefato avançar, com o professor circulando e intervindo por perguntas. A proporção entre as duas está declarada na mecânica da disciplina e não se repete aqui: o que importa ao plano é a ordem, que é sempre teoria antes de tutoria, porque a tarefa de projeto de um módulo é a aplicação do que aquele módulo ensinou, nunca o contrário.
Essa ordem tem uma consequência que orienta a leitura de todo o documento. A teoria é o eixo; o Projeto Integrador é a aplicação. Um módulo não se define pela entrega que o grupo tem de fazer, e sim pelo que se aprende nele — a tarefa vem depois, como uso daquilo. Sempre que a redação de um módulo parecer partir do que o grupo precisa entregar, o módulo está invertido e a correção é reescrever pelo conteúdo.
A articulação entre as duas metades acontece por um mecanismo simples e repetido. O que o professor constrói ao vivo na metade teórica é a implementação de referência, que permanece disponível como exemplo resolvido; o que o grupo constrói na tutoria é o artefato dele, espelhado naquele, com andaime decrescente ao longo do percurso. Nos primeiros módulos, o grupo recebe estrutura sugerida, casos de teste prontos e revisão detalhada; no arco intermediário, projeta sozinho e defende as decisões; no arco final, integra e responde por consequências de escolhas feitas módulos antes. O desvanecimento do apoio é deliberado, e é ele que transfere autonomia sem sobrecarregar no início nem manter dependência no fim.
Nada é pedido fora do horário de aula, e nenhuma atividade proposta é alheia ao Projeto Integrador. As duas metades da regra importam. A primeira protege o estudante que trabalha, para quem tarefa extraclasse é barreira de acesso e não exigência de rigor. A segunda impede que a disciplina se dissolva em exercícios avulsos: se uma atividade não faz o projeto do grupo avançar, ela está competindo com ele pelo tempo do estudante. A mecânica desta oferta comporta tutoria em sala, de modo que o Projeto Integrador acontece dentro da aula e não se aplica o desenho alternativo de projeto extraclasse.
Estrutura Geral de Cada Módulo
A condução segue um padrão estável, e a estabilidade é intencional: quando a forma do encontro é previsível, a atenção do estudante fica disponível para o conteúdo em vez de ser gasta em descobrir o que vai acontecer.
A metade teórica abre retomando o problema que o módulo anterior deixou em aberto e enunciando, em uma frase, o que ao final se conseguirá fazer e não se conseguia antes. Segue-se a exposição, que não é contínua: ela é intercalada com questões conceituais de múltipla escolha, respondidas primeiro individualmente, depois discutidas em duplas e respondidas de novo. Essa técnica é a principal ferramenta ativa da metade teórica, opera inteiramente dentro do encontro e não pressupõe estudo prévio — nenhum documento desta disciplina supõe que o estudante leu antes, e a inversão da sala é variante possível de condução, nunca o roteiro padrão. O bloco final da metade teórica é a construção ao vivo: o professor escreve o código do módulo passo a passo, verbalizando cada decisão, enquanto os estudantes acompanham reproduzindo em seus próprios ambientes.
As sessões de tutoria abrem com os grupos retomando onde pararam e declarando em voz alta o que pretendem concluir naquele encontro — declaração curta, que existe para tornar visível o grupo que não sabe o que fazer a seguir, que é o sintoma mais confiável de que a teoria não foi compreendida. O trabalho interno segue em programação em pares com revezamento explícito de papéis, e o professor circula intervindo por pergunta antes de intervir por indicação. O encerramento é a atualização do diário de atividades e uma rodada rápida de revisão entre pares, em que um grupo executa o artefato de outro sobre uma entrada que o autor não escolheu.
A fronteira entre o que acompanha e o que compõe nota precisa estar clara para o professor e para a turma. As questões conceituais da metade teórica, a revisão entre pares na tutoria, o rascunho comentado, os exercícios discutidos e o diário de atividades são acompanhamento formativo: geram devolutiva imediata e não geram nota. Os instrumentos que compõem nota são poucos, estão fixados na seção de avaliação ao final deste documento e não se multiplicam por módulo. Criar entregas com nota “para manter o aluno ativo” é a sobrecarga que o desenho avaliativo desta disciplina evita de propósito, e não é o que mantém ninguém ativo.
Linguagens formais e a arquitetura de um compilador
Objetivos do Módulo
Estabelecer o vocabulário formal do percurso e o mapa do sistema que será construído, de modo que cada módulo seguinte possa ser localizado dentro de um todo. Ao final, o estudante deve descrever, sem consulta, o caminho completo que um trecho de texto percorre da primeira letra lida até o resultado executável, e situar cada fase quanto ao que consome e ao que produz.
Competências a Serem Desenvolvidas
Formalizar em notação de gramática uma linguagem antes descrita de modo intuitivo.
Situar uma classe de linguagem na hierarquia que relaciona gramáticas e máquinas.
Ler a arquitetura de um sistema de tradução como sequência de artefatos, e não de rótulos.
Habilidades a Serem Adquiridas
Operar com alfabeto, cadeia e linguagem como conjunto, e com união, concatenação e fecho.
Distinguir a metade que analisa da metade que sintetiza, e nomear o artefato de fronteira entre elas.
Escrever, em notação formal, um exemplo válido da linguagem que o próprio grupo vai tratar.
Conteúdo a Ser Apresentado
Alfabetos, cadeias e operações sobre cadeias; linguagem como conjunto de cadeias; união, concatenação e fecho. A hierarquia que faz corresponder classes de gramáticas a classes de máquinas, apresentada como tabela que os módulos seguintes converterão em código. Anatomia do compilador: as fases, o que cada uma consome e produz, a distinção entre análise e síntese, e a posição da interpretação e das formas intermediárias. Fecha-se com a primeira especificação formal da linguagem de domínio do percurso.
Tarefas do Projeto Integrador
Tarefa 1: Fixar o recorte da linguagem
Decida sobre que domínio os padrões da sua linguagem vão falar, que classe de padrões o seu sistema aceitará, que forma terá a descrição escrita por quem o usa e o que ele produzirá ao processá-la. É um texto curto e consequente: tudo o que vem nos capítulos seguintes responde a ele, e cada ambiguidade deixada aqui reaparece adiante como retrabalho, quando já existe código apoiado sobre a decisão que faltou.
Confira o recorte, item a item, contra as propriedades que o capítulo do projeto enumera — o usuário escrevendo padrões, os símbolos da própria linguagem saindo do mesmo motor, o aninhamento na gramática, os tipos e o escopo, o objeto produzido e o pedido do domínio que a máquina finita não atende. A conferência custa dez minutos aqui; a propriedade que faltar só se manifesta no capítulo que dependia dela, e aí o conserto alcança tudo o que já foi construído em cima.
A tentação natural é começar largo e restringir depois. O caminho barato é o inverso: comece pelo menor recorte que ainda seja interessante de processar e amplie quando a peça correspondente estiver funcionando. Um recorte generoso escrito no primeiro capítulo não acelera nada — apenas transfere para o meio do percurso a decisão de abandoná-lo. Note que essa economia vale para o tamanho do recorte, não para as propriedades acima: cortar operadores é barato e reversível; descobrir tarde que o domínio escolhido não sustenta uma delas, não.
Tarefa 2: Escrever à mão um exemplo válido
Escreva, sem apoio de nenhum programa, um exemplo de descrição válida no recorte que acabou de fixar, e registre ao lado dele o que se espera que o sistema faça ao recebê-lo. Este par — entrada e resultado pretendido — é o primeiro caso de verificação do percurso, e continuará sendo usado muito depois de existirem centenas de outros: é ele que o analisador de símbolos precisará reconhecer por inteiro, que a gramática precisará derivar e que o sistema completo precisará processar do começo ao fim.
Tarefa 3: Criar o repositório de trabalho
Monte o repositório com as três partes que sustentam um sistema construído por acumulação: a apresentação, que diz o que o sistema faz e como se compila e executa; a documentação, que guarda a especificação da linguagem, o registro das decisões técnicas e o diário da construção; e o código, organizado por responsabilidade. Deixe o comando único que reconstrói tudo e roda os casos existentes funcionando desde já, ainda que haja pouquíssimo a compilar — ele é a única defesa contra a regressão silenciosa numa peça considerada pronta, e instalá-lo depois custa mais do que parece.
Esta etapa se conclui sem uma linha de código escrita, e é essa a razão pela qual costuma ser subestimada. O que ela produz são decisões: o recorte, o exemplo e o lugar onde o sistema vai crescer.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
A metodologia dominante aqui é a aprendizagem baseada em problema: a exposição parte de um texto que o sistema deveria processar e da pergunta de como se chega dele ao resultado, e a arquitetura emerge como resposta. As questões conceituais deste módulo funcionam bem sobre classificação — dada uma linguagem, a que classe pertence — porque o erro típico é confundir a complexidade aparente do texto com a classe formal.
Ponto de atenção: este é o módulo em que os grupos mais subestimam o trabalho, por não haver código a escrever. Um grupo que sai da tutoria sem um exemplo escrito da própria linguagem e sem o repositório criado começa o módulo seguinte devendo, e a dívida só aparece três módulos depois. Cobre o artefato de decisão, não a impressão de que “está tudo entendido”.
Expressões regulares e linguagens regulares
Objetivos do Módulo
Tratar a expressão regular como objeto matemático com sintaxe e semântica próprias, e não como recurso prático de uso corrente. Ao final, o estudante deve escrever a expressão correta para uma especificação dada em prosa e decidir se duas expressões distintas denotam a mesma linguagem.
Competências a Serem Desenvolvidas
Especificar formalmente um conjunto de cadeias por meio de uma notação declarativa.
Reduzir notação de conveniência a um núcleo mínimo de operadores, e justificar a redução.
Raciocinar sobre equivalência de especificações, e não apenas sobre a correção de uma delas.
Habilidades a Serem Adquiridas
Determinar a linguagem denotada por uma expressão dada, incluindo casos de borda.
Aplicar as propriedades de fechamento para compor especificações sem sair da classe.
Converter classes de caracteres e quantificadores em composições do núcleo.
Conteúdo a Ser Apresentado
Sintaxe e semântica das expressões regulares; a linguagem denotada por cada construção. Classes de caracteres, quantificadores e abreviações apresentadas como açúcar sintático sobre um núcleo pequeno. Propriedades de fechamento das linguagens regulares e o que elas garantem ao compor especificações. Equivalência entre expressões distintas, com casos em que a intuição falha.
Tarefas do Projeto Integrador
Tarefa 1: Escrever a especificação do que você vai construir
Escolha um dos assuntos propostos e escreva, por extenso, o que o seu sistema fará. O documento é em Markdown, fica versionado junto do código e é o texto ao qual você voltará em todos os capítulos seguintes para conferir se o que está construindo ainda é o que pretendia construir.
A escolha do assunto é a decisão mais cara de desfazer do percurso inteiro. Trocá-lo no meio custa o que já foi construído; testá-lo aqui, enquanto ele é só um texto, custa uma tarde. Assunto próprio, fora dos propostos, é aceito desde que a especificação responda às perguntas que fecham a lista de propostas — todas, por escrito.
O vocabulário desta tarefa. Faltam doze capítulos para os termos abaixo ganharem a definição precisa. Aqui basta a versão curta, que é o suficiente para escrever o documento.
Padrão — a descrição de uma forma que trechos da entrada podem ter. Entrada — o texto ou a sequência que o sistema lê e examina. Reconhecer — decidir se um trecho da entrada tem a forma que um padrão descreve. Regra — o que o sistema faz quando reconhece algo. Aninhamento — uma construção que contém outra do mesmo tipo por dentro, sem limite fixo de profundidade. Objeto — o arquivo que o tradutor grava ao terminar, contendo o que a máquina precisa para trabalhar. Execução — o momento, posterior e separado, em que outro componente lê o objeto e o roda sobre uma entrada. Verificação — o exame que o tradutor faz antes de gravar o objeto, e que pode recusar o que está escrito.
Sete seções compõem o documento. Cada uma responde a uma pergunta, e cada uma tem um sinal característico de que saiu errada.
1. O domínio e a cena. Pergunta: sobre o que fala a sua linguagem, e quem se beneficiaria de escrevê-la? Descreva o domínio, a pessoa que escreveria algo nessa linguagem e o que ela quer obter. Sinal de erro: a seção descreve um programa em vez de um domínio — se ela fala em arquivos, laços e estruturas, ainda não chegou à cena.
2. O que se escreve na linguagem. Pergunta: como é, na prática, um texto escrito nela? Mostre de três a cinco exemplos completos, inventados por você, do mais simples ao mais elaborado. Escreva-os como se a linguagem já existisse. Sinal de erro: os exemplos são todos variações do mesmo formato — sinal de que a linguagem tem uma construção só, e uma construção só não sustenta o percurso.
3. O que o sistema aceita e o que recusa. Pergunta: dado um texto qualquer, o que faz dele válido? Descreva as formas aceitas e, para cada tipo de erro previsível, o que o sistema responde — a mensagem que a pessoa recebe e o que ela consegue fazer com essa mensagem. Sinal de erro: a seção lista o que é aceito e cala sobre o inválido. Metade do uso real de qualquer linguagem é descobrir por que o que se escreveu não funcionou.
4. Onde a linguagem se aninha. Pergunta: que construção da sua linguagem contém outra do mesmo tipo por dentro, sem profundidade máxima? Aponte-a e mostre um exemplo com três níveis. Sinal de erro: não existe nenhuma. Uma linguagem cujos comandos são todos de formato fixo dispensa metade do que este percurso ensina, e a lacuna aparecerá tarde, quando já houver código escrito.
5. O que se verifica antes de rodar. Pergunta: que texto está bem escrito e mesmo assim não faz sentido? Descreva os erros que o sistema apanha antes de executar qualquer coisa: um nome usado sem ter sido declarado, dois valores de naturezas incompatíveis combinados, uma referência a algo que não existe. Nomeie as naturezas de valor que a sua linguagem distingue. Sinal de erro: todos os valores são da mesma natureza e nada pode ser usado errado. Sem incompatibilidade possível, não há o que verificar.
6. O que o sistema produz, e quem executa. Pergunta: o que fica gravado quando o tradutor termina, e quem lê aquilo depois? Descreva o objeto produzido — o que ele contém, em que ordem — e o componente separado que o lê e o executa sobre uma entrada, possivelmente noutro momento, com o tradutor já encerrado. Sinal de erro: a resposta é “o sistema mostra o resultado”. Mostrar o resultado na hora é uma coisa; gravar um objeto que outra coisa executa depois é outra, e é a segunda que este percurso constrói.
7. A pergunta que você vai responder medindo. Pergunta: que dúvida sobre o seu sistema não se resolve olhando, só medindo? Escreva a pergunta, a grandeza que a responde, a abordagem de referência contra a qual ela será comparada e — este é o campo que se costuma pular — o resultado que contrariaria a sua expectativa. Sinal de erro: a pergunta tem resposta conhecida antes da medida, ou a comparação é contra nada. Qualquer coisa ganha do vazio.
O que a especificação não pede, e por bom motivo. Nada de arquitetura, estrutura de dados, biblioteca ou algoritmo. Faltam doze capítulos para essas decisões terem base, e antecipá-las produz um documento copiado de fora que ninguém entende e ninguém segue. Descreva comportamento: o que existe na cena, o que a pessoa faz, o que o sistema aceita, o que recusa e como avisa.
Duas restrições valem sobre qualquer assunto escolhido, e ambas já foram enunciadas. Nenhum gerador automático de analisador entra no sistema: o reconhecimento nasce de máquinas construídas à mão, e essa é a razão de o percurso existir. E o sistema tem de funcionar sem depender do sistema operacional de quem o compila — nada de recurso exclusivo de uma plataforma.
Vale reler a especificação pronta procurando o assunto que parece bom e falha: o que executa direto sem gravar objeto, o que tem comandos de formato fixo sem aninhamento, o que trata todo valor como sendo da mesma natureza e o que toma o reconhecedor pronto de uma biblioteca. Os quatro passam despercebidos na leitura entusiasmada da própria proposta, que é a única leitura que ela recebe antes de o código começar.
Tarefa 2: Escolher o núcleo mínimo de operadores
Decida quais operadores de padrão o seu sistema tratará de fato e quais notações de conveniência serão reduzidas a esse núcleo antes de qualquer processamento. A escolha parece pequena e determina o tamanho de tudo o que vem depois: cada operador mantido no núcleo reaparece em todas as peças seguintes, na construção da máquina, na conversão para forma determinística e na tradução final. Registre a decisão junto com as reduções, na forma de pares que mostrem a notação de partida e a expressão equivalente no núcleo.
O critério de inclusão é a impossibilidade de reduzir. Um operador que se exprime pela composição de outros é conveniência de quem escreve o padrão, não capacidade nova do sistema — e mantê-lo no núcleo multiplica por três o trabalho de cada capítulo seguinte em troca de nada.
Tarefa 3: Ler a expressão e convertê-la em árvore
Implemente a leitura de uma expressão de padrão e a sua conversão em uma estrutura em árvore, com a precedência e a associatividade dos operadores refletidas na forma da árvore, e não em convenção escrita à parte. Esta é a primeira peça de código do sistema, e o primeiro ponto em que uma decisão de representação passa a ter consequência: a árvore produzida aqui é exatamente o que a construção da máquina consumirá no capítulo seguinte.
A tarefa se cumpre quando duas notações diferentes para o mesmo padrão convergem para a mesma estrutura. Essa convergência é a verificação mais barata que existe desta etapa, e a que detecta o erro mais comum, que é a redução aplicada de forma inconsistente.
Tarefa 4: Recusar a expressão malformada com a posição do problema
Faça o sistema recusar expressões malformadas apontando onde está o problema. Encerrar a execução informando apenas que a expressão é inválida é metade do trabalho, e a metade que não serve a quem escreveu a expressão: a mensagem existe para que alguém corrija o texto, e uma mensagem sem posição obriga essa pessoa a procurar. Trate esta tarefa como requisito técnico e não como acabamento — o custo de acrescentar a posição depois, quando a leitura já está distribuída em vários pontos do código, é várias vezes maior do que o de carregá-la desde o começo.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
A construção ao vivo começa aqui e não para mais: o professor escreve a leitura de expressões passo a passo, verbalizando por que reduzir ao núcleo antes de processar. As questões conceituais rendem muito neste módulo, porque a maioria dos estudantes traz uso prático sem definição, e um par de itens sobre equivalência costuma revelar essa lacuna diante de toda a turma.
A escolha do tema acontece na tutoria deste módulo, e é o ponto de maior alavancagem do semestre inteiro. As vinte propostas não se repetem entre grupos: o professor organiza a ordem de escolha, registra quem ficou com o quê e mantém a lista visível, porque dois grupos que descobrem tarde ter escolhido o mesmo assunto perdem os dois. Grupo que queira tema próprio, fora das vinte, responde por escrito às perguntas de decisão que fecham a lista — e só com elas respondidas o tema é aceito.
A especificação produzida aqui é entrega parcial com devolutiva e sem nota própria: ela compõe a entrega parcial do Projeto Integrador, e o que o professor devolve é a conferência do recorte contra a cobertura da ementa, tópico a tópico. É a conferência mais barata do semestre e a que evita o prejuízo mais caro — um recorte que orfana geração de código descoberto no módulo 13 não se conserta, porque o que existe foi construído sobre a lacuna.
Ponto de atenção, e este vale por todos os outros deste módulo: a especificação que descreve um sistema que executa direto, sem gravar objeto algum, é aprovada sem esforço por quem a lê depressa — ela cobre reconhecimento, estrutura e verificação com competência. A pergunta que a desmonta em segundos é “mostre onde está escrito o que fica gravado quando o tradutor termina, e quem lê aquilo depois”. Faça-a em toda especificação, inclusive nas que parecem impecáveis.
Ponto de atenção: o erro estrutural do módulo é o grupo tentar tratar todos os operadores de conveniência diretamente, em vez de reduzi-los. O sintoma aparece como código que cresce sem parar e nunca fecha. Intervenha por pergunta — “quantos casos o seu tratamento precisa distinguir, e quantos precisaria se você reduzisse antes?” — em vez de indicar a solução.
Autômatos finitos determinísticos
Objetivos do Módulo
Introduzir a máquina e, com ela, a primeira decisão de representação que cobra preço mensurável em memória. Ao final, o estudante deve projetar um autômato para uma especificação dada — não apenas simular um autômato pronto — e justificar por que o conjunto de estados escolhido é suficiente.
Competências a Serem Desenvolvidas
Projetar uma máquina de estados a partir de uma especificação em prosa.
Converter uma definição matemática em estrutura de dados, com consciência do custo.
Tratar o caso inválido como parte do projeto, e não como exceção a resolver depois.
Habilidades a Serem Adquiridas
Definir formalmente um autômato e executar o reconhecimento como sequência de configurações.
Representar a função de transição e estimar seu consumo em função do tamanho do alfabeto.
Incorporar estado de erro explícito e reportar recusa de forma útil.
Conteúdo a Ser Apresentado
Definição formal como quíntupla, função de transição total e conjunto de estados de aceitação. Configuração, passo de computação e reconhecimento de cadeia. Projeto de autômatos para especificações dadas. A tabela de transição como estrutura de dados, com as alternativas de representação e o que cada uma custa. Autômatos com estado de erro e tratamento de entrada inválida.
Tarefas do Projeto Integrador
Tarefa 1: Decidir a representação da função de transição
Escolha como armazenar a função de transição da máquina e justifique a escolha por escrito, dizendo quanto a representação ocupa em função do tamanho do alfabeto e do número de estados, e qual alternativa você descartou e por quê. Esta é a primeira decisão do percurso que cobra preço mensurável, e o hábito de registrar a conta será exigido de novo, em escala maior, no fecho do sistema.
A decisão tem alcance maior do que aparenta neste ponto. A tabela de transição é também a forma daquilo que o sistema vai produzir ao final, quando o objeto emitido precisar carregar as máquinas construídas a partir da descrição lida. Representá-la mal cobra duas vezes, e a segunda cobrança chega quando já não há tempo de refazer.
Tarefa 2: Executar uma máquina descrita à mão
Implemente a execução de uma máquina de estados, descrita à mão, sobre uma cadeia de entrada, reportando aceitação ou recusa. O gerador só existe no capítulo seguinte, e chegar lá com o executor já verificado separa dois erros que, juntos, são difíceis de distinguir: a máquina errada e a execução errada.
Trate explicitamente o símbolo para o qual não há transição prevista. É o caso que a definição formal costuma resolver com uma frase e que, no código, decide se o sistema recusa a cadeia ou termina de forma imprevisível diante de uma entrada que ninguém antecipou.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Este é o primeiro módulo em que a cultura maker rende de fato: desenhar a máquina no quadro, em grupo, antes de qualquer código, e só então traduzi-la em estrutura. O exemplo resolvido do professor mostra a representação escolhida e a descartada, porque é a comparação que ensina, não a escolha isolada.
Ponto de atenção: grupos tendem a implementar a simulação e considerar o módulo concluído, pulando o projeto. A verificação é pedir que projetem uma máquina para uma especificação nova, na hora, sem consultar a anterior. Um segundo ponto, mais silencioso: a decisão de representação tomada aqui atravessa todo o resto do percurso, e grupos que a tomam sem justificar pagam caro no módulo de determinização.
Autômatos não determinísticos e a construção de Thompson
Objetivos do Módulo
Apresentar o não determinismo como ferramenta de construção, e não como curiosidade teórica, e converter a especificação declarativa do segundo módulo em máquina por procedimento mecânico. Ao final, o estudante deve executar a construção à mão sobre uma expressão de tamanho moderado e reconhecer, no código que a implementa, cada caso da definição que a origina.
Competências a Serem Desenvolvidas
Reconhecer numa definição indutiva o algoritmo que ela induz.
Compor blocos com interface uniforme para obter uma construção sistemática.
Simular uma máquina com múltiplos caminhos simultâneos sem confundir simulação com determinização.
Habilidades a Serem Adquiridas
Operar transições vazias e calcular o fecho vazio de um conjunto de estados.
Aplicar a construção caso a caso: base, concatenação, união e fecho.
Verificar o resultado comparando a simulação com a determinação feita à mão.
Conteúdo a Ser Apresentado
Não determinismo, transições vazias e aceitação por existência de caminho. Fecho vazio como operação básica da simulação. A construção que traduz cada operador da expressão em um bloco de máquina com uma entrada e uma saída, com os casos base e as composições. Por que a construção é sistemática e o que isso significa para quem a implementa.
Tarefas do Projeto Integrador
Tarefa 1: Converter a árvore em máquina não determinística
Implemente a construção que transforma a estrutura em árvore produzida pela leitura de padrões em uma máquina não determinística. A tarefa se cumpre quando qualquer expressão aceita pela leitura produz uma máquina — sem exceção reservada para um operador que ficou de fora, porque um operador não coberto aqui reaparece como falha silenciosa três capítulos adiante, sobre uma entrada que ninguém escreveu à mão.
Vale registrar no diário da construção uma observação sobre esta etapa: a construção teórica se transcreve quase diretamente em código, praticamente sem adaptação. É o único ponto do percurso em que isso acontece de forma tão limpa, e perceber a diferença entre este caso e os seguintes é parte do que se aprende aqui.
Tarefa 2: Simular a máquina não determinística
Implemente a simulação que executa a máquina construída sobre uma cadeia de entrada. A dificuldade não está no algoritmo, e sim em manter a coleção de estados simultaneamente ativos sem que o custo dessa manutenção domine a execução — o que exige decidir como representar um conjunto de estados, e não apenas um estado.
Tarefa 3: Montar a bateria de casos conferidos à mão
Construa um conjunto de casos em que o resultado da simulação é comparado com o que você determinou à mão, cadeia por cadeia. Casos conferidos à mão são caros de produzir e é justamente por isso que valem: eles são a única evidência independente do próprio código, e a partir daqui todas as peças do sistema serão verificadas contra alguma coisa que o sistema mesmo produziu. Guarde-os no repositório e mantenha-os rodando pelo comando único de reconstrução — a partir do capítulo seguinte, é essa bateria que vai avisar quando a máquina reduzida deixar de aceitar o que a original aceitava.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
O par construção ao vivo e exemplo resolvido está no seu melhor uso aqui, porque a distância entre a definição no quadro e o código na tela é a menor de todo o percurso — e mostrar isso explicitamente é o ponto pedagógico do módulo. Vale conduzir a construção à mão, no quadro, para uma expressão pequena, antes de qualquer linha de código.
Ponto de atenção: o defeito recorrente é o grupo tentar produzir diretamente a máquina determinística, “para economizar uma etapa”. O resultado é um código que funciona nos casos simples e falha em união e fecho, e o diagnóstico custa muito mais do que a etapa economizada. Antecipe isso na abertura da tutoria, porque depois de escrito o código o grupo resiste a descartá-lo.
Determinização e minimização
Objetivos do Módulo
Fechar o ciclo que transforma uma especificação declarativa em máquina eficiente, e estabelecer o hábito de medir o efeito de uma transformação. Ao final, o estudante deve comprovar a equivalência entre a máquina obtida e a original por comparação sobre um conjunto de cadeias, e relatar a contagem de estados antes e depois da redução.
Competências a Serem Desenvolvidas
Demonstrar equivalência entre duas famílias de máquinas por construção, e não por analogia.
Avaliar o custo de uma transformação e decidir quando ele importa na prática.
Medir o efeito de uma otimização em vez de afirmá-lo.
Habilidades a Serem Adquiridas
Executar a construção de subconjuntos e reconhecer o crescimento de estados que ela pode gerar.
Identificar estados indistinguíveis e obter a máquina mínima por refinamento de partições.
Verificar equivalência por bateria de cadeias, e não por inspeção visual do diagrama.
Conteúdo a Ser Apresentado
A construção de subconjuntos e a equivalência entre as duas famílias. Explosão de estados: o custo do determinismo e as condições em que ele se manifesta. Estados equivalentes, relação de indistinguibilidade e a noção de máquina mínima. Algoritmos de minimização por refinamento de partições, com demonstração de correção nos pontos acessíveis.
Tarefas do Projeto Integrador
Tarefa 1: Converter a máquina para a forma determinística
Implemente a conversão da máquina não determinística em uma máquina determinística equivalente. Esta é a peça mais reaproveitada de todo o sistema, e a razão é estrutural: o mesmo componente serve ao reconhecimento dos símbolos da própria linguagem, mais adiante, e à compilação dos padrões que o usuário escreve nela, no fecho. Uma peça, dois níveis — o que torna cada defeito deixado aqui um defeito que aparece duas vezes, em contextos que parecem não ter relação um com o outro.
Tarefa 2: Reduzir a máquina ao número mínimo de estados
Implemente a redução ao número mínimo de estados. É o que transforma um reconhecedor correto porém caro em algo utilizável, e é também o primeiro momento em que o sistema devolve um número que mede o efeito de uma decisão sua.
Faça o próprio sistema reportar a contagem de estados antes e depois da redução. Um número que só existe quando alguém se lembra de contá-lo à mão vale como impressão, e nunca como medida: ele deixa de ser produzido exatamente nas ocasiões em que seria mais interessante, que são aquelas em que o resultado surpreende.
Tarefa 3: Evidenciar a equivalência e o crescimento de estados
Demonstre que a máquina reduzida aceita exatamente a mesma linguagem que a original, por comparação sobre um conjunto de cadeias — nunca por inspeção visual do diagrama, que é a forma mais confiável de concordar consigo mesmo. A bateria de casos montada no capítulo anterior serve diretamente a isso.
Construa também, de propósito, um caso de crescimento acentuado no número de estados, e observe-o acontecer. O fenômeno é conhecido em teoria e raramente é vivido; construir o caso e ver o número subir é o que separa saber que a explosão existe de saber quando ela ameaça o seu próprio sistema.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Este módulo produz a peça mais reaproveitada do sistema, e vale dizê-lo à turma: o cuidado investido aqui é recuperado em todos os módulos seguintes. A construção ao vivo deve incluir a instrumentação que conta os estados, porque é ela que torna a otimização observável — e é o mesmo hábito que o último módulo do percurso vai exigir em escala maior.
Ponto de atenção: dois defeitos convivem aqui. O primeiro é a verificação de equivalência por olhar o diagrama, que passa em todos os casos exceto naquele que importa. O segundo é o grupo declarar a minimização “funcionando” sem nenhum caso em que ela efetivamente reduza estados. Peça o número, sempre; sem contagem antes e depois, não há afirmação a avaliar.
O lema do bombeamento e os limites do reconhecimento regular
Objetivos do Módulo
Demonstrar que a maquinaria construída até aqui tem um limite, e que o limite é demonstrável. Ao final, o estudante deve conduzir o argumento sobre um caso concreto e delimitar com precisão o que o resultado autoriza a concluir e o que não autoriza — distinção que separa quem entendeu de quem memorizou.
Competências a Serem Desenvolvidas
Ler e reproduzir um argumento de refutação com alternância de quantificadores.
Reconhecer a necessidade de mudar de classe a partir de uma impossibilidade provada.
Distinguir prova de impossibilidade de ausência de solução conhecida.
Habilidades a Serem Adquiridas
Enunciar o lema com a ordem correta dos quantificadores e identificar quem escolhe o quê.
Aplicá-lo ao caso dos delimitadores balanceados, por inteiro.
Construir, no próprio artefato, um caso que exibe a falha e explicá-lo como necessária.
Conteúdo a Ser Apresentado
Intuição do limite: memória finita e repetição forçada de estados em cadeias longas. Enunciado do lema e sua estrutura lógica como argumento de refutação. Aplicação a linguagens não regulares, com o caso dos delimitadores balanceados conduzido por inteiro. O que o resultado autoriza a concluir e o que não autoriza, com contraexemplos de aplicação incorreta.
Tarefas do Projeto Integrador
Tarefa 1: Construir o padrão que excede o reconhecedor
Escreva, na linguagem que você definiu, um padrão que exija contagem irrestrita — delimitadores balanceados é o caso canônico, e construções aninhadas dentro de construções do mesmo tipo servem igualmente. Submeta-o ao seu reconhecedor e observe o que acontece. O caso precisa ser reproduzível por outra pessoa a partir do que está escrito no repositório: um resultado que só aparece na máquina de quem o produziu não demonstra nada.
Tarefa 2: Explicar por que a falha é necessária
Escreva um texto curto que acompanhe o caso e sustente a afirmação difícil: a falha observada não é defeito da sua implementação, e nenhuma correção dentro daquela classe de máquinas a resolveria. É o argumento que separa uma limitação teórica de um erro de programação, e a diferença entre os dois não é visível na tela — os dois se manifestam como uma entrada que deveria ser aceita e não é.
Esta é a etapa em que o sistema demonstra o próprio limite, e o que se produz aqui é a explicação da falha. Sem esse limite provado sobre o seu próprio código, a subida a uma classe mais expressiva de máquinas pareceria uma escolha de organização do assunto, em vez da consequência necessária que de fato é.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Este módulo tem conteúdo teórico denso e, ainda assim, produz artefato: a demonstração executável da falha. A ordem de condução que funciona é inversa à intuitiva — primeiro executar o caso que quebra, no artefato que a turma construiu, e só então formalizar por que ele tinha de quebrar. A surpresa vem antes da prova, e é ela que sustenta a atenção durante a prova.
Ponto de atenção: o erro mais comum na aplicação do lema é o estudante escolher o que cabe ao adversário escolher. Trate a estrutura do argumento explicitamente como um jogo de alternância, com os papéis nomeados. E vigie a conclusão indevida: falhar em aplicar o lema não prova que a linguagem é regular, e essa inferência aparece em quase toda turma.
Análise léxica
Objetivos do Módulo
Converter a máquina teórica em componente de software com interface definida, e introduzir os problemas que só aparecem quando vários padrões concorrem pela mesma posição do texto. Ao final, o estudante deve ter um reconhecedor que consome o texto da própria linguagem e entrega uma sequência de símbolos com posição de origem.
Competências a Serem Desenvolvidas
Especificar o conjunto de símbolos de uma linguagem por meio de expressões regulares.
Resolver concorrência entre especificações por regra explícita, e não por acaso de implementação.
Projetar a interface entre dois componentes de um sistema de tradução.
Habilidades a Serem Adquiridas
Distinguir token, lexema e padrão, e dizer o que a fase entrega à seguinte.
Implementar casamento mais longo e desempate entre padrões concorrentes.
Transportar posição no texto e produzir mensagem de erro léxico localizada.
Conteúdo a Ser Apresentado
Token, lexema e padrão; o que o analisador léxico entrega ao sintático. Especificação dos símbolos da linguagem por expressões regulares. A regra do casamento mais longo e a resolução de conflitos entre padrões concorrentes. Espaços, comentários e erros léxicos. Posição no texto como dado transportado. Interação inicial com a tabela de símbolos, em forma mínima.
Tarefas do Projeto Integrador
Tarefa 1: Reaproveitar o reconhecedor como componente com interface
Transforme o reconhecedor construído até aqui em um componente com interface definida, e faça o sistema ler a própria descrição escrita pelo usuário instanciando esse mesmo componente sobre outra especificação. Não há reconhecimento novo a escrever: o que muda é a especificação alimentada ao que já existe.
Código de reconhecimento novo, escrito em paralelo ao que já funciona, é defeito de projeto e não avanço — e aqui o defeito é especialmente caro, porque destrói justamente a economia estrutural que sustenta o sistema inteiro. Se a interface do componente não permite reaproveitá-lo, o que precisa mudar é a interface, não a decisão de reaproveitar.
Tarefa 2: Quebrar a descrição em símbolos com posição
Faça o sistema percorrer a descrição de exemplo e produzir a sequência de símbolos que a representa, com cada símbolo carregando a sua posição no texto de origem. Espaços e comentários são descartados, mas descartá-los não pode custar a posição dos símbolos que vêm depois — é o erro mais comum desta etapa, e ele só se manifesta muito adiante, quando uma mensagem de erro aponta para o lugar errado e a suspeita recai sobre a peça errada.
A tarefa se cumpre quando a descrição escrita à mão no primeiro capítulo é reconhecida por inteiro, sem sobra e sem símbolo desconhecido.
Tarefa 3: Responder ao caractere inválido
Faça um caractere que não pertence à linguagem produzir uma mensagem que diga onde ele está. É a primeira vez que o sistema responde a quem escreveu a descrição, e não a quem escreveu o sistema; daqui em diante, cada capítulo acrescenta uma família nova de recusas, e todas herdam a forma decidida agora.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
O momento pedagógico do módulo é mostrar que nada de novo se constrói: o reconhecedor é o componente dos módulos anteriores instanciado sobre outra especificação. Conduza a construção ao vivo de modo a tornar esse reaproveitamento visível — se o código do lexer parecer uma peça nova, a mensagem se perdeu.
Ponto de atenção: o defeito de projeto típico é o grupo escrever um reconhecedor à parte, específico da linguagem, duplicando o que já tinha. Detecte perguntando qual componente executa o reconhecimento; se a resposta descrever código novo, há duplicação a desfazer antes de avançar. Segundo ponto: a posição no texto costuma ser deixada “para depois” e nunca é acrescentada, e sem ela todos os erros dos módulos seguintes ficam mudos.
Gramáticas livres de contexto
Objetivos do Módulo
Subir de classe depois do limite provado, e formar competência de projeto de gramática, não apenas de leitura. Ao final, o estudante deve escrever a gramática da própria linguagem, transformá-la para caber na estratégia de análise adotada e defender cada transformação aplicada.
Competências a Serem Desenvolvidas
Projetar uma gramática adequada a uma linguagem pretendida, e não apenas interpretar uma dada.
Reconhecer ambiguidade e avaliar suas consequências sobre a tradução.
Expressar precedência e associatividade na própria estrutura das regras.
Habilidades a Serem Adquiridas
Construir derivações à esquerda e à direita e a árvore correspondente.
Remover recursão à esquerda, direta e indireta, e justificar a necessidade.
Aplicar fatoração à esquerda e verificar o efeito sobre a decisão local do analisador.
Conteúdo a Ser Apresentado
Definição formal; derivações mais à esquerda e mais à direita; árvore de derivação como registro da estrutura. Ambiguidade: origem, consequências e técnicas de eliminação. Precedência e associatividade escritas na gramática. Transformações preparatórias: remoção de recursão à esquerda, direta e indireta, e fatoração à esquerda, com a explicação de por que sem elas o analisador do módulo seguinte não funciona.
Tarefas do Projeto Integrador
Tarefa 1: Escrever por extenso a gramática da sua linguagem
Escreva a gramática da linguagem que o seu sistema aceita, por extenso e por completo, sem recursão à esquerda e devidamente fatorada, com a precedência e a associatividade dos operadores expressas na própria estrutura das regras — e não em uma tabela à parte que o analisador teria de consultar. Esta é a etapa de projeto mais exigente do percurso: quase não há código a escrever, e é justamente por isso que ela costuma ser tratada como se fosse rápida.
A gramática não descreve uma linguagem nova. Ela descreve, com precisão que o texto do primeiro capítulo não tinha, a mesma linguagem que você fixou lá. Se ao escrevê-la você descobrir que precisa mudar o recorte, mude — e registre a mudança. O que não pode acontecer é a gramática e o recorte descreverem coisas diferentes, cada um servindo de referência a uma peça distinta do sistema.
Tarefa 2: Derivar o exemplo passo a passo
Exiba a derivação completa, passo a passo, do exemplo escrito à mão no primeiro capítulo a partir da gramática que você acabou de escrever. É a verificação que não admite atalho: uma gramática que não deriva o próprio exemplo de referência está errada, ou o exemplo está fora do recorte, e as duas descobertas são baratas agora e caras depois que o analisador existir.
Tarefa 3: Registrar cada transformação aplicada
Para cada transformação que você aplicou à gramática — eliminação de recursão à esquerda, fatoração, ajuste de precedência —, registre a forma anterior ao lado da forma final. É a comparação que torna a transformação compreensível meses depois, quando a gramática precisar mudar e ninguém mais lembrar por que aquela regra tem a forma estranha que tem. Registrar apenas o resultado guarda o que o sistema precisa e perde o que você precisa.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Módulo de projeto, e a tutoria muda de natureza: não há código a depurar, há decisão a defender. O formato que funciona é a revisão entre pares — cada grupo tenta derivar, com a gramática de outro, um texto que o autor não previu. A metodologia de design thinking cabe aqui de fato, e não como enfeite: prototipar a gramática, testá-la contra casos reais e iterar é literalmente o trabalho do módulo.
Ponto de atenção: este é o módulo com maior risco de dívida silenciosa de todo o percurso. Um grupo que sai com a gramática “quase pronta” gasta a tutoria do módulo seguinte depurando recursão à esquerda em vez de construir o analisador, e perde os dois módulos. Trate a gramática transformada como condição de saída, e verifique-a derivando um exemplo na frente do grupo.
Autômatos de pilha
Objetivos do Módulo
Estabelecer o elo teórico entre a gramática e o reconhecedor, e explicitar por que, nesta classe, determinismo e não determinismo deixam de ser equivalentes. Ao final, o estudante deve explicar, sobre a própria gramática, que decisão local o analisador terá de tomar e com que informação contará para tomá-la.
Competências a Serem Desenvolvidas
Relacionar uma classe de gramáticas à classe de máquinas que a reconhece.
Avaliar o efeito de uma restrição de memória sobre o poder de reconhecimento.
Antecipar a consequência prática de uma propriedade teórica sobre o projeto de um analisador.
Habilidades a Serem Adquiridas
Definir formalmente a máquina e operar seus dois critérios de aceitação.
Argumentar a equivalência entre a máquina e a gramática correspondente.
Explicar por que a distinção entre determinismo e não determinismo muda de natureza aqui.
Conteúdo a Ser Apresentado
Definição formal; a pilha como memória auxiliar de acesso restrito. Aceitação por estado final e por pilha vazia, e a equivalência entre os dois critérios. Equivalência entre a máquina e as gramáticas livres de contexto. Determinismo e não determinismo nesta classe, e por que a distinção não reproduz a do caso finito.
Tarefas do Projeto Integrador
Módulo teórico quanto ao projeto: não há tarefa prática do Projeto Integrador aqui, e por isso este bloco não carrega enunciado. A realização concreta do modelo estudado é o analisador do módulo seguinte, e antecipá-la significaria implementar antes de entender por quê. O que se pede aos grupos neste módulo é entendimento verificável, registrado no diário da construção: sobre a própria gramática, que decisão local o analisador precisará tomar em cada ponto e com que informação contará para tomá-la. A condução desse registro está na subseção seguinte.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Módulo conceitual: não há código de projeto a produzir, e a realização concreta do modelo é o analisador do módulo seguinte. A condução ganha com instrução por pares em dose maior que a média, porque as questões conceituais sobre poder de reconhecimento são exatamente do tipo que a discussão entre colegas resolve melhor que a exposição.
Ponto de atenção: sem artefato a construir, a tutoria deste módulo é a que mais facilmente se dissolve. Use-a para uma dívida útil: revisão da gramática do módulo anterior e escrita do argumento sobre a decisão local do analisador. Os grupos que ainda carregam gramática mal transformada são recuperáveis aqui, e só aqui — no módulo seguinte já será tarde.
Análise sintática descendente
Objetivos do Módulo
Construir o analisador e a estrutura que as fases seguintes consumirão, com tratamento de erro dirigido a quem escreve o texto de entrada. Ao final, o estudante deve produzir a árvore esperada para o texto de exemplo, projetá-la como estrutura própria e prosseguir após um erro em vez de encerrar no primeiro problema.
Competências a Serem Desenvolvidas
Traduzir uma gramática transformada em um reconhecedor, reconhecendo a correspondência estrutural.
Projetar uma representação intermediária adequada ao consumo posterior, e não à derivação.
Tratar erro como requisito de projeto, com o usuário do sistema como destinatário.
Habilidades a Serem Adquiridas
Calcular os conjuntos de primeiros e de seguidores e usá-los na decisão de análise.
Verificar a condição que caracteriza as gramáticas analisáveis com um símbolo de antecipação.
Implementar as duas variantes, recursiva e dirigida por tabela, e comparar o que cada uma expõe.
Conteúdo a Ser Apresentado
A estratégia descendente e a correspondência entre não terminais e procedimentos. Conjuntos de primeiros e de seguidores: construção e uso. A condição de analisabilidade com um símbolo de antecipação, verificada sobre casos concretos. Analisador recursivo e variante dirigida por tabela. Detecção, relato e recuperação de erros. Construção da árvore sintática abstrata como saída da fase.
Tarefas do Projeto Integrador
Tarefa 1: Projetar a árvore como estrutura própria
Projete a estrutura em árvore que representa a descrição lida, distinta da derivação que a gramática induz. A derivação registra como a gramática chegou àquele texto; a árvore registra o que as etapas seguintes precisam consumir, e as duas coisas raramente coincidem. Nós que existem apenas para resolver precedência, por exemplo, cumpriram a sua função na derivação e não têm por que sobreviver na estrutura.
O critério é direto e vale campo a campo: cada campo da estrutura precisa ser justificável por um consumidor posterior nomeado. Campo sem consumidor é campo a remover — e o custo de mantê-lo é a obrigação de preenchê-lo corretamente em todos os pontos que constroem a árvore, para sempre.
Tarefa 2: Construir o analisador descendente
Implemente o analisador que consome a sequência de símbolos e produz essa árvore. É a etapa de maior volume de código do percurso, e a que mais recompensa o trabalho feito na gramática: cada regra bem fatorada se transcreve quase mecanicamente, e cada regra mal transformada exige uma decisão local que o código não tem informação para tomar.
A tarefa se cumpre quando a descrição de exemplo produz a árvore esperada — a mesma que você consegue desenhar à mão a partir da derivação do capítulo anterior.
Tarefa 3: Recuperar-se do erro em vez de encerrar
Faça uma descrição sintaticamente inválida produzir uma mensagem dirigida a quem a escreveu, e faça o analisador prosseguir depois do erro em vez de encerrar no primeiro problema. A diferença entre as duas condutas é a diferença entre um sistema que aponta os cinco problemas de uma descrição em uma passada e um que obriga quem a escreveu a corrigir um, executar de novo, descobrir o seguinte, e repetir cinco vezes. A segunda conduta é mais fácil de implementar e é a razão pela qual muita ferramenta é desagradável de usar.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Módulo de maior volume de implementação, e o que mais se beneficia da programação em pares com revezamento rígido: sem rodízio, a implementação se concentra em um integrante e os demais chegam à etapa final sem saber explicar a fase central do artefato. É também o módulo em que o andaime começa a desvanecer de forma perceptível — a orientação passa a ser por pergunta, e o grupo decide.
Ponto de atenção: a árvore sintática abstrata é o ponto crítico. Grupos que a fazem espelhar a derivação da gramática produzem uma estrutura inflada que as fases seguintes precisam constantemente contornar, e o custo aparece dois módulos adiante, quando já é caro corrigir. Peça, na tutoria, que o grupo justifique cada campo da estrutura pelo consumo posterior; campo sem consumidor é campo a remover.
Análise sintática ascendente
Objetivos do Módulo
Formar critério de escolha entre as duas famílias de analisadores, com argumento técnico. Ao final, o estudante deve dizer, sobre a própria gramática, o que mudaria se a estratégia fosse a outra, que conflitos apareceriam e o que eles revelariam sobre a gramática.
Competências a Serem Desenvolvidas
Comparar duas estratégias pelo poder de reconhecimento e pelo custo de construção.
Ler um conflito como informação sobre a gramática, e não como defeito da ferramenta.
Avaliar o que uma ferramenta automatiza e que decisões ela toma em silêncio por quem a usa.
Habilidades a Serem Adquiridas
Executar deslocamento e redução à mão sobre um caso pequeno, identificando o handle.
Construir o autômato de itens e a tabela correspondente em exemplos reduzidos.
Diagnosticar um conflito e dizer que ambiguidade ou que falta de antecipação o origina.
Conteúdo a Ser Apresentado
A estratégia de deslocamento e redução; pilha de análise e a noção de handle. Itens, autômato de itens e construção das tabelas em casos pequenos, feitos à mão. As famílias de analisadores ascendentes e o poder de reconhecimento de cada uma. Conflitos e sua interpretação diagnóstica. Geradores automáticos de analisadores: o que automatizam, o que continua sendo decisão de projeto e o que assumem sem avisar.
Tarefas do Projeto Integrador
Módulo teórico quanto ao projeto: não há tarefa prática do Projeto Integrador aqui, e por isso este bloco não carrega enunciado. O artefato segue o caminho descendente por inteiro, e a ausência é decisão declarada, não omissão. O que se pede aos grupos é um argumento escrito e curto: diante da própria gramática, o que mudaria se a estratégia fosse a ascendente, que conflitos apareceriam e o que eles revelariam sobre a gramática. O critério é a qualidade técnica do argumento, não a extensão dele, e a condução está na subseção seguinte.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Módulo conceitual e comparativo: não há código de projeto a produzir, por decisão declarada — o percurso segue o caminho descendente por inteiro, e construir uma segunda família completa custaria mais do que renderia. O ferramental do artefato é construído à mão em toda a disciplina, e é justamente por isso que este módulo pode tratar os geradores com honestidade: o estudante já sabe o que eles fariam por ele, porque fez.
Ponto de atenção: há risco de o módulo soar como conteúdo dispensável, já que não entra no artefato. Contrarie isso desde a abertura apresentando um conflito real numa gramática pequena e pedindo o diagnóstico — a competência aqui é diagnóstica, e ela se avalia. Use a tutoria para escrita do argumento de escolha e para recuperação de grupos atrasados na fase anterior.
Análise semântica
Objetivos do Módulo
Introduzir a primeira fase que mantém conhecimento acumulado sobre o texto inteiro, e tratar a qualidade da mensagem de erro como requisito técnico. Ao final, cada condição de invalidez prevista pela linguagem do grupo deve produzir mensagem específica, e um texto válido deve atravessar a verificação sem falso alarme.
Competências a Serem Desenvolvidas
Projetar uma estrutura de conhecimento acumulado com escopo, e não apenas uma tabela.
Especificar um sistema de tipos e as combinações que a linguagem recusa.
Descrever formalmente o fluxo de informação sobre uma árvore.
Habilidades a Serem Adquiridas
Implementar tabela de símbolos com escopo aninhado, inserção e consulta.
Verificar tipos, aridade e declaração antes do uso, com mensagem específica por caso.
Distinguir atributos sintetizados de herdados e relacionar a ordem de avaliação à estratégia de análise.
Conteúdo a Ser Apresentado
O que a sintaxe não captura: declaração antes do uso, compatibilidade de tipos, aridade. Tabela de símbolos: organização, escopo aninhado, inserção e consulta. Sistemas de tipos elementares; verificação, inferência local e conversão, incluindo os tipos próprios do domínio da linguagem tratada. Gramáticas de atributos e esquemas de tradução dirigidos pela sintaxe; atributos sintetizados e herdados; ordem de avaliação. Qualidade das mensagens de erro semântico.
Tarefas do Projeto Integrador
Tarefa 1: Registrar e consultar os nomes declarados
Faça o sistema manter conhecimento acumulado sobre a descrição inteira, e não apenas sobre a posição corrente da leitura: os nomes declarados passam a ser registrados quando aparecem e consultados quando são usados, e uma referência a nome inexistente é recusada. É a primeira estrutura do percurso que não corresponde a nenhum trecho específico do texto de entrada — ela existe entre os trechos, e essa mudança de natureza é o que torna esta etapa mais difícil do que o volume de código sugere.
Tarefa 2: Verificar a compatibilidade dos tipos
Verifique as comparações e operações escritas pelo usuário quanto à compatibilidade do que elas relacionam: o que se pode comparar com o quê, e sobre que combinações cada operação faz sentido. A regra precisa estar escrita na especificação da linguagem antes de estar no código — descobrir a regra enquanto se implementa a verificação produz um sistema cujo comportamento ninguém consegue prever sem ler a implementação.
Tarefa 3: Produzir mensagem específica para cada invalidez
Faça cada condição de invalidez prevista pela sua linguagem produzir uma mensagem específica, dizendo o que se esperava e o que se encontrou. Uma mensagem genérica para dez situações diferentes custa menos para escrever e devolve ao usuário o trabalho de descobrir qual das dez ocorreu.
Verifique também o caso oposto, que é a metade mais fácil de esquecer: uma descrição inteiramente válida precisa atravessar a verificação sem nenhum falso alarme. Uma verificação que recusa o que é legítimo é pior do que verificação nenhuma, porque ensina quem usa o sistema a ignorar o que ele diz.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
O estudo de caso rende aqui como em nenhum outro módulo: apresentar mensagens de erro reais de sistemas conhecidos, boas e ruins, e pedir o diagnóstico do que a mensagem revela sobre a fase que a produziu. A discussão tem lado técnico e lado humano — alguém do outro lado da mensagem está tentando terminar um trabalho —, e é uma das poucas oportunidades naturais do percurso para tratar consequência humana de decisão técnica sem forçar a barra.
Ponto de atenção: o defeito quase universal é testar apenas os casos inválidos e nunca verificar que um texto válido atravessa sem falso alarme. Um verificador que recusa tudo passa em toda bateria de erro. Peça sempre as duas metades. Segundo ponto: mensagens genéricas do tipo “erro de tipo” satisfazem o grupo e não satisfazem ninguém mais; exija que a mensagem diga o que se esperava e o que se encontrou.
Ambientes de execução
Objetivos do Módulo
Estabelecer o mundo para dentro do qual o código será gerado e fixar por extenso o formato do que será emitido. Ao final, esse formato deve estar escrito de modo que outra pessoa consiga carregá-lo sem perguntar nada ao grupo, com um exemplo preenchido à mão.
Competências a Serem Desenvolvidas
Derivar de uma especificação de máquina as restrições que o gerador terá de respeitar.
Especificar um formato de saída como contrato legível por terceiros.
Relacionar noções de escopo e tempo de vida a endereços concretos.
Habilidades a Serem Adquiridas
Descrever a organização da memória de um programa em execução e o papel de cada região.
Explicar o registro de ativação, a passagem de parâmetros e o retorno.
Documentar o formato emitido com um exemplo completo preenchido manualmente.
Conteúdo a Ser Apresentado
Organização da memória de um programa em execução: código, área estática, pilha e área dinâmica. Registro de ativação; passagem de parâmetros, valor de retorno e endereço de retorno. Escopo em tempo de execução e acesso a nomes não locais. Alocação dinâmica e estratégias de recuperação de memória, em panorama. Modelos de execução e as restrições impostas pela máquina alvo definida para o percurso.
Tarefas do Projeto Integrador
Tarefa 1: Definir e justificar o modelo de execução
Defina o mundo em que o resultado produzido pelo seu sistema vai rodar: como o objeto emitido é executado, o que existe durante essa execução e o que se mantém entre um trecho de entrada e o seguinte. Justifique a escolha contra a alternativa que você descartou. É uma etapa com pouco código e muita consequência, e essa proporção é o que a torna fácil de adiar.
Tarefa 2: Fixar por extenso o formato do objeto produzido
Escreva por extenso o formato do que será produzido, com um exemplo preenchido à mão para uma descrição mínima. Este formato é o contrato entre as duas metades do sistema — a que analisa e a que executa — e é a única peça que as liga. Registre também as restrições que o gerador terá de respeitar ao emitir contra esse formato, porque é a ausência delas, e não a ausência do formato, que costuma aparecer tarde demais.
O critério de conclusão é operacional e não admite autoavaliação: alguém que não participou da escrita precisa conseguir preencher um exemplo lendo apenas a especificação, sem perguntar nada a você. Especificação que só o próprio autor entende equivale a especificação inexistente, e o custo dela aparece no capítulo seguinte, quando o gerador precisa emitir contra um contrato que não existe.
Tarefa 3: Tornar disponíveis os dados reconhecidos
Defina como os dados reconhecidos durante a execução ficam disponíveis a quem consome o resultado — o que se guarda, sob que forma e por quanto tempo. É a parte da especificação que parece detalhe de implementação e não é: ela decide o que o sistema consegue produzir como saída, e portanto o que ele serve para fazer.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Módulo de especificação com pouco código e muita consequência, e a tutoria deve refletir isso: o produto do encontro é um documento, não um programa. A revisão entre pares é o instrumento natural — um grupo tenta interpretar o formato especificado por outro, sem ajuda, e o que ficou ambíguo aparece imediatamente.
Ponto de atenção: grupos tratam a especificação do formato como formalidade e escrevem meia página vaga, descobrindo o custo no módulo seguinte, quando o gerador precisa emitir contra um contrato que não existe. O teste é operacional e barato: entregue a especificação de um grupo a outro e peça que preencham um exemplo. Se não conseguirem, a especificação não está pronta, por mais bem escrita que pareça.
Geração de código
Objetivos do Módulo
Fechar o percurso com o sistema produzindo algo executável, e converter a avaliação do resultado em medida numérica. Ao final, o percurso completo deve funcionar sobre um texto de partida que ninguém preparou, e o grupo deve sustentar com números o efeito de pelo menos uma decisão de tradução.
Competências a Serem Desenvolvidas
Justificar a existência de uma representação intermediária em vez da tradução direta.
Selecionar instruções contra um repertório fixo, tratando as operações ausentes dele.
Avaliar o efeito de uma otimização por medição, e não por afirmação.
Habilidades a Serem Adquiridas
Traduzir a árvore sintática abstrata para a representação intermediária, caso a caso.
Aplicar as otimizações elementares com critério de aplicabilidade, e não como receita.
Contar o que foi emitido, comparar duas decisões e sustentar a conclusão com os números.
Conteúdo a Ser Apresentado
Representações intermediárias: código de três endereços e formas baseadas em pilha; por que existe uma camada intermediária. Tradução da árvore sintática abstrata para essa representação. Seleção de instruções e emissão para a máquina alvo, incluindo a expansão de operações ausentes do repertório disponível. Otimizações elementares e independentes de máquina, com critério de aplicabilidade de cada uma. Avaliação do resultado por contagem de instruções emitidas e custo de execução.
Tarefas do Projeto Integrador
Tarefa 1: Emitir o objeto a partir da árvore verificada
Implemente a produção do objeto no formato especificado, a partir da árvore que passou pela verificação. É o fecho do caminho que começou no primeiro capítulo, e o ponto em que decisões tomadas muito antes cobram ou economizam: a forma da árvore, a representação da tabela de transição e o núcleo de operadores escolhido determinam, os três, quanto trabalho existe aqui.
Tarefa 2: Executar o objeto sobre entrada real
Ponha o sistema em execução de ponta a ponta: da entrada escrita na sua linguagem até o resultado observável, com o objeto emitido efetivamente executado — pelo motor que você construiu ou pelo ambiente de execução que escolheu como alvo —, sobre um caso que ninguém preparou para o teste. Implemente e demonstre também a regra que resolve a ambiguidade que a sua linguagem admite: onde mais de uma leitura é possível no mesmo ponto, o sistema precisa escolher, e a escolha precisa estar escrita antes de estar no código.
Entrada que ninguém preparou é o critério mais simples de enunciar e o mais frequentemente ausente. Um sistema que processa corretamente os três exemplos escritos por quem o construiu, e falha no primeiro arquivo real, está ajustado aos próprios casos, e ainda não pronto. As duas respostas aceitáveis são o resultado correto e uma recusa explicando o que há de errado com a entrada.
Uma exigência acompanha esta execução e decide se existe um sistema ou um conjunto de peças que se parecem com um: nenhuma etapa pode receber entrada montada à mão. Os símbolos que o reconhecedor produz são os que o analisador consome, a árvore que o analisador constrói é a que a verificação anota, e a árvore anotada é a que alimenta a emissão. Etapas demonstradas em separado, cada uma com um dado preparado para a demonstração dela, imitam o percurso inteiro sem o realizar — e a imitação sobrevive a toda verificação parcial, caindo apenas nesta, que é feita de um comando só.
Tarefa 3: Medir duas decisões e sustentar o julgamento
Produza ao menos uma medida numérica comparando duas decisões técnicas: a quantidade de estados antes e depois da redução, o número de instruções emitidas para uma mesma construção sob duas formas de tradução, ou o volume de entrada processado por unidade de tempo. Registre a medida por escrito, com o método usado para obtê-la.
O que fecha o percurso é o julgamento que o número sustenta: o que se ganharia mudando a decisão medida, o que se perderia e por que a escolha feita se defende. O que se cobra é argumento defensável, e nunca uma resposta única correta — a diferença entre quem construiu entendendo e quem transcreveu de algum lugar aparece inteira nesse ponto.
Estratégias Pedagógicas e Pontos de Atenção na Tutoria
Módulo de integração, e a condução tem duas tarefas simultâneas: fechar o conteúdo e preparar a defesa individual que virá depois. A orientação da tutoria concentra-se em consequências de decisões tomadas módulos antes, que é exatamente o que a arguição verifica. O estudo de caso final do percurso é a discussão sobre quem paga o custo de uma operação cara — se o projeto da máquina, se o tradutor, se quem escreve na linguagem —, e ela deve ser conduzida como decisão de engenharia com três respostas defensáveis, não como pergunta com gabarito.
Ponto de atenção: o risco terminal do percurso é o grupo chegar aqui com peças que nunca foram integradas, descobrindo na última tutoria que o sistema não atravessa ponta a ponta. Isso não se corrige neste módulo — previne-se cobrando integração desde o arco intermediário. Segundo ponto, específico deste módulo: aceite apenas afirmações com número. “Ficou mais eficiente” não é resultado; a contagem antes e depois é.
Avaliação e Critérios
O desenho avaliativo desta disciplina tem três estágios com funções distintas e não intercambiáveis, e confundi-los é o erro que ele existe para impedir. A avaliação diagnóstica identifica o ponto de partida da turma e é aplicada antes do primeiro módulo do percurso. A avaliação contínua é acompanhamento formativo ao longo do período, com muitos momentos de devolutiva e poucos instrumentos que geram nota — acompanhar continuamente não significa atribuir nota continuamente. A avaliação final é integração de competências, e aqui ela é o Projeto Integrador somado à defesa individual.
A avaliação diagnóstica de pré-requisitos não compõe nota, e isso é constitutivo dela. Ela é aplicada antes que o primeiro módulo de conteúdo comece e existe para que o professor descubra, por tópico, quais pré-requisitos a turma não domina e com que ênfase conduzir a remediação. Atribuir-lhe peso a converteria em prova, e o estudante passaria a chutar em vez de revelar o que não sabe — destruindo exatamente o dado que ela deveria produzir.
Os componentes que compõem nota e seus pesos são fixos e nenhum documento gerado os altera:
| Estágio | Componente | Natureza | Peso |
|---|---|---|---|
| Contínua | Entregas parciais do Projeto Integrador | Grupo | 15% |
| Contínua | Verificação de teoria por bloco de módulos | Individual | 5% |
| Contínua | Engajamento no estudo pelo aplicativo | Individual | 20% |
| Contínua | Pontualidade nas entregas | Grupo | 10% |
| Final | Projeto Integrador: produto, documentação e apresentação | Grupo | 20% |
| Final | Arguição sobre o projeto | Individual | 30% |
O desenho não é uma distribuição arbitrária de percentuais, e convém que a razão dele esteja explícita para quem conduz a disciplina. Numa disciplina inteiramente organizada em torno de um projeto de grupo, existe um risco estrutural: um estudante atravessar o período sem jamais demonstrar domínio próprio, carregado pelo trabalho dos colegas. Os dois componentes individuais — a verificação de teoria e a arguição — existem para eliminar esse risco, e somados respondem por trinta e cinco por cento da nota, o bastante para que um carona reprove mesmo integrando um bom grupo. Reduzir, diluir ou tornar opcional qualquer um dos dois desmonta a garantia.
A verificação individual de teoria é aplicada por blocos de módulos, cujo recorte é definido no conteúdo programático da disciplina e não se repete aqui — reproduzir o agrupamento em dois documentos faria os dois divergirem na primeira correção feita em apenas um. O que cabe a este plano registrar é a natureza do instrumento: individual, feito em aula, sem consulta, medindo exclusivamente a teoria do bloco e nunca a tarefa de projeto do grupo. É essa separação que o torna informativo, e a devolutiva imediata pelo comentário que acompanha cada alternativa é o que o mantém formativo apesar de gerar nota.
A rubrica do Projeto Integrador é divulgada com a proposta do trabalho, nunca na devolução da nota. Ela é publicada no documento do Projeto Integrador e carrega uma dimensão obrigatória de contribuição individual, que distingue quem participou e explica as próprias escolhas de quem participou e não sabe explicar a própria parte. Essa dimensão é o instrumento anti-carona do dia a dia, alimentado pelo diário de atividades, pela observação nas sessões de tutoria e pela avaliação entre pares — e é ela que dá sentido à arguição final. Cada nível de cada dimensão descreve o que o caracteriza, de modo que devolver o resultado ao grupo seja leitura da rubrica e não improviso de parecer.
A arguição individual recai sobre o artefato que o grupo do estudante construiu e tem duas partes. Na primeira, o estudante percorre o código que escreveu e justifica uma decisão técnica dele, nomeando a alternativa descartada — o critério é explicar por que não é de outro jeito. Na segunda, o professor toma uma fase vizinha do mesmo artefato e faz uma pergunta de consequência. Quem participou da construção responde mesmo sem ter digitado aquele arquivo, porque acompanhou as decisões; quem foi carregado não tem como reconstruir isso na hora.
Uso de inteligência artificial e integridade. A regra é combinada no início, por escrito, e publicada junto com a proposta do projeto. A inteligência artificial é apoio legítimo na exploração de alternativas de projeto, na revisão de código já escrito, no esclarecimento de conceito, no diagnóstico de erro de compilação e na revisão do texto da documentação — usos em que o estudante permanece autor da decisão, e é a decisão que se avalia. A autoria é obrigatoriamente própria nos dois momentos individuais, a arguição e a verificação de teoria, ambos realizados em aula, sem consulta e sem assistente: são os pontos em que se verifica domínio pessoal, e a mediação de uma ferramenta destruiria o dado. No projeto, o uso é admitido desde que registrado no diário e desde que cada integrante saiba explicar e defender o código que consta como dele — código que o autor declarado não sabe explicar é tratado como não sendo dele, qualquer que seja a origem. Constitui plágio apresentar como próprio trabalho de terceiro sem indicação de origem, e a consequência recai individualmente sobre quem o praticou, não sobre o grupo inteiro.
Quanto à sequência, a avaliação contínua se encerra com folga antes da avaliação final, e a entrega final do Projeto Integrador ocorre na semana seguinte à conclusão do último módulo de conteúdo. Nenhuma data absoluta é fixada neste documento, que é reaproveitado de um período para outro: a autoridade sobre datas é o calendário acadêmico vigente, comunicado à turma no início do período.