Autor
Afiliações

Moacyr Francischetti Corrêa, Bacharel em Ciência da Computação, Licenciado em Computação, Especialista em Ciência de Dados e Inteligência Artificial, PhD em Biotecnologia in Silico

Descrição da Disciplina

Compiladores e Linguagens Formais e Autômatos ocupa uma posição peculiar no Bacharelado em Ciência da Computação: é a disciplina em que a teoria mais abstrata do curso encontra o artefato de engenharia mais concreto que o estudante terá construído até aqui. De um lado estão os modelos formais de computação — alfabetos, gramáticas, autômatos, a hierarquia de Chomsky —, objetos matemáticos que existem independentemente de qualquer máquina. De outro está o compilador, um programa que lê texto e produz um programa executável, e cuja arquitetura interna é, fase por fase, a materialização direta daqueles modelos. Poucas disciplinas oferecem uma correspondência tão nítida entre uma teoria e uma implementação.

Essa correspondência é o argumento pedagógico central do curso. O analisador léxico não é apenas um trecho de código que separa palavras: é um autômato finito determinístico executando. O analisador sintático não é apenas uma rotina que verifica parênteses: é um autômato de pilha percorrendo uma gramática livre de contexto. Quando o estudante compreende que essas equivalências não são analogias didáticas, mas identidades, ele passa a enxergar o compilador como uma consequência necessária da teoria, e não como um amontoado de técnicas acumuladas por tradição. É essa mudança de percepção que a disciplina persegue.

O título da disciplina funde dois campos que muitos currículos separam em duas disciplinas distintas — uma de linguagens formais e autômatos, outra de construção de compiladores. A fusão traz uma vantagem e um risco. A vantagem é que a teoria nunca aparece descolada da sua aplicação: o estudante estuda a construção de subconjuntos na mesma semana em que precisa dela para fazer o analisador léxico funcionar. O risco é o inverso: que a teoria seja atropelada pela pressa de fazer o compilador andar, reduzindo os autômatos a uma etapa burocrática escondida atrás de um gerador de analisadores léxicos. A disciplina foi desenhada para capturar a vantagem e neutralizar o risco, e é por isso que nada de essencial é delegado a ferramentas automáticas: o analisador léxico e o analisador sintático são construídos à mão, do zero, precisamente para que a teoria continue visível no código.

O fio condutor da disciplina é um artefato único, construído de forma cumulativa ao longo dos quinze módulos. Trata-se de uma pequena linguagem de domínio específico para reconhecimento de padrões em texto, à qual damos o nome de Peneira, no espírito das ferramentas clássicas de filtragem de texto. Um programa nessa linguagem declara padrões e regras de ação, e o produto da compilação é um motor de autômatos capaz de varrer um fluxo de entrada e reagir aos casamentos encontrados. A escolha não é arbitrária. Nela, a teoria de autômatos comparece duas vezes no mesmo artefato: os símbolos da própria linguagem são reconhecidos por autômatos construídos a partir de expressões regulares, e os padrões que o usuário declara são compilados exatamente pelo mesmo mecanismo. Um único módulo de construção de autômatos serve os dois níveis. Essa economia estrutural é o argumento que fecha a teoria em sala: o estudante vê a matéria que acabou de estudar virando a ferramenta que executa a matéria.

O que distingue esta disciplina. O compilador é construído à mão, sem geradores automáticos de analisadores. Não se trata de rejeitar essas ferramentas — elas são estudadas e o estudante precisa saber que existem e quando usá-las —, mas de reconhecer que quem nunca implementou a construção de subconjuntos não compreende de fato o que um gerador de analisadores léxicos faz por ele. A ferramenta vem depois do entendimento, nunca no lugar dele.

A construção do artefato de referência é conduzida pelo professor em sala, com os estudantes acompanhando e reproduzindo o código em seus próprios ambientes, e o resultado permanece disponível como exemplo resolvido para consulta posterior. Paralelamente, cada grupo de estudantes concebe e implementa o seu próprio Projeto Integrador, tomando o artefato do professor como modelo de referência, não como algo a copiar. O andaime oferecido pelo professor diminui deliberadamente ao longo do semestre: os primeiros módulos trazem mais estrutura e passos guiados, e os últimos exigem que o grupo resolva sozinho parcelas cada vez maiores do problema.

Público-alvo

A disciplina é oferecida no sexto termo do Bacharelado em Ciência da Computação, em regime presencial, com carga horária de cento e vinte horas. O estudante que chega até aqui já percorreu metade do curso e traz uma bagagem específica que a disciplina pressupõe e explora.

Do primeiro termo, ele traz Lógica Computacional e Matemática Discreta, que fornecem a linguagem em que a teoria de linguagens formais é expressa: conjuntos, relações, funções, indução e prova. A definição formal de um autômato é uma quíntupla de conjuntos e funções, e a demonstração de que dois autômatos reconhecem a mesma linguagem é uma prova por indução; quem não estiver confortável com esse vocabulário sentirá dificuldade nos primeiros módulos. Do segundo termo vem Estrutura de Dados, talvez o pré-requisito mais diretamente utilizado: tabelas de dispersão para a tabela de símbolos, pilhas para o analisador sintático e para a máquina de execução, árvores para a representação intermediária. Vem também Programação Orientada a Objetos, que informa a organização modular do compilador.

Do terceiro e do quinto termos vêm Arquitetura e Organização de Computadores e Design de Processador de Computador, que sustentam a parte final do curso: quem já projetou um processador e compreende conjuntos de instruções, registradores e organização de memória tem o repertório necessário para entender geração de código e ambientes de execução como problemas de engenharia concretos, e não como abstrações. Do quarto termo vem Resolução de Problemas de Grafos, cujos algoritmos reaparecem em toda parte — os autômatos são grafos dirigidos, e a análise de fluxo de controle opera sobre grafos —, e Paradigmas de Linguagem de Programação, que dá ao estudante o distanciamento necessário para tratar linguagens de programação como objetos de estudo, e não apenas como ferramentas de trabalho. Do quinto termo vem ainda Sistemas Operacionais, pertinente ao estudo dos ambientes de execução.

O projeto pedagógico do curso não estabelece pré-requisito formal para esta disciplina. A relação acima descreve a bagagem efetivamente disponível na progressão dos termos e o uso que a disciplina faz dela, não uma exigência regimental. O módulo de nivelamento existe para recuperar esses fundamentos com quem precisar, em particular a notação de conjuntos e a demonstração por indução, que costumam ser o ponto de atrito real.

Espera-se um estudante capaz de programar com autonomia em uma linguagem de sistemas, confortável com ponteiros, alocação de memória e estruturas de dados encadeadas, e disposto a trabalhar em grupo de dois ou três integrantes ao longo de todo o semestre. Não se espera familiaridade prévia com teoria de linguagens formais nem com qualquer ferramenta de construção de compiladores.

Objetivos de Aprendizagem

Ao final da disciplina, o estudante deve ser capaz de transitar com desenvoltura entre a especificação formal de uma linguagem e a implementação do programa que a reconhece. Isso significa, no plano teórico, saber definir formalmente autômatos finitos determinísticos e não determinísticos, gramáticas livres de contexto e autômatos de pilha; demonstrar a equivalência entre modelos quando ela existe; e, sobretudo, reconhecer os limites de cada modelo — saber argumentar por que uma linguagem não é regular é tão importante quanto saber construir o autômato de uma que seja, porque é essa fronteira que justifica a existência das fases seguintes do compilador.

No plano da implementação, o estudante deve ser capaz de converter uma expressão regular em um autômato não determinístico, determinizá-lo e minimizá-lo, e usar o resultado como núcleo de um analisador léxico funcional. Deve saber escrever uma gramática não ambígua para uma linguagem pequena, calcular os conjuntos que orientam a análise descendente e implementar um analisador sintático por descida recursiva com recuperação de erros. Deve compreender os métodos ascendentes com profundidade suficiente para avaliar quando são preferíveis e para interpretar os conflitos que um gerador de analisadores reporta, ainda que a implementação manual da disciplina siga o caminho descendente.

Deve ainda ser capaz de projetar e povoar uma tabela de símbolos com tratamento de escopos, implementar verificações semânticas e de tipos por tradução dirigida por sintaxe, escolher uma representação intermediária adequada ao problema, e gerar código executável para uma máquina abstrata de pilha. Deve compreender como o programa em execução organiza sua memória, o papel dos registros de ativação e o que o compilador precisa emitir para que a execução funcione. E deve conhecer o vocabulário básico da otimização — blocos básicos, grafo de fluxo de controle, transformações locais — o suficiente para reconhecer oportunidades e entender o que um compilador de produção faz depois que o código intermediário está pronto.

Transversalmente, espera-se que o estudante desenvolva a capacidade de conduzir um projeto de software de médio porte em equipe, ao longo de um semestre inteiro, com decisões de arquitetura tomadas cedo e sustentadas até o fim — uma experiência que a maioria das disciplinas anteriores, organizadas em exercícios curtos, não proporciona. A avaliação por pares que acompanha as entregas parciais e a entrega final existe para tornar essa dimensão visível e discutível.

Ementa

A ementa oficial da disciplina, conforme o projeto pedagógico do curso, compreende análise léxica, análise sintática, análise semântica, ambientes de execução, geração de código e o projeto e implementação de um compilador. Os conteúdos de linguagens formais e autômatos, embora nomeados no título e nos objetivos institucionais, não aparecem itemizados na ementa como tópicos autônomos: comparecem como pressuposto transversal de todas as fases. A organização em quinze módulos apresentada a seguir torna esse pressuposto explícito, dedicando os módulos iniciais à fundamentação formal e conduzindo cada resultado teórico diretamente à fase do compilador que o utiliza.

A sequência segue a ordem natural da hierarquia de Chomsky e, simultaneamente, a ordem de construção do artefato condutor: o estudante estuda as linguagens regulares e constrói o analisador léxico; estuda as linguagens livres de contexto e constrói o analisador sintático; estuda semântica, execução e geração de código e completa o compilador. Ao final do sétimo módulo o front-end léxico está operacional, o que oferece um ponto natural de consolidação e entrega parcial no meio do semestre.

A indicação de profundidade que acompanha cada módulo considera que a exposição teórica dispõe de duas aulas por módulo, ficando as quatro restantes reservadas à tutoria do Projeto Integrador. Profundidade instrumental significa que o tópico é tratado até o ponto em que o estudante consegue implementá-lo. Profundidade conceitual significa que o objetivo é o entendimento e a capacidade de avaliar e decidir, sem exigência de implementação. Profundidade panorâmica significa reconhecimento e vocabulário, suficientes para leitura posterior autônoma.

Módulo 1: Panorama da Compilação e Linguagens Formais

Abertura da disciplina e construção do mapa mental que orientará todo o semestre. O que significa compilar e o que distingue um compilador de um interpretador, de um montador e de um transpilador. A decomposição clássica em fases, com a distinção entre front-end e back-end, e a razão de ser dessa separação. Panorama da hierarquia de Chomsky, apresentando os quatro tipos de gramáticas e as classes de linguagens correspondentes, com a indicação de quais delas a disciplina percorrerá e por quê. Apresentação do artefato condutor: o problema que a linguagem Peneira resolve, a forma dos seus programas e o motivo de o produto da sua compilação ser um motor de autômatos. Organização do ambiente de trabalho e da estrutura do projeto.

Profundidade: panorâmica, com ancoragem no artefato. Nenhum tópico é esgotado; o objetivo é que o estudante saiba, ao sair, onde cada assunto do semestre se encaixa e o que estará construindo.

Módulo 2: Alfabetos, Linguagens e Expressões Regulares

Fundamentos formais. Símbolos, alfabetos, cadeias e as operações sobre cadeias: concatenação, potência, reverso, prefixo e sufixo. Linguagens como conjuntos de cadeias, e as operações sobre linguagens: união, concatenação, fecho de Kleene e fecho positivo. Expressões regulares como notação finita para linguagens potencialmente infinitas, com sua sintaxe, sua semântica e as identidades algébricas que permitem simplificá-las. A distinção entre as expressões regulares da teoria e as das bibliotecas de programação, que incluem construções não regulares. Especificação da mini-linguagem de expressões regulares que o artefato condutor aceitará.

Profundidade: instrumental. O estudante precisa ler, escrever e manipular expressões regulares com fluência, e precisa saber demonstrar equivalências simples entre elas por manipulação algébrica.

Módulo 3: Autômatos Finitos Determinísticos

O primeiro modelo de máquina do curso. Definição formal do autômato finito determinístico como quíntupla, com a função de transição, a configuração instantânea e a função de transição estendida sobre cadeias. Linguagem reconhecida por um autômato. Representação por diagrama de estados e por tabela de transição, e a passagem de uma forma à outra. Projeto de autômatos a partir da descrição informal de uma linguagem, com atenção aos estados de erro e à completude da função de transição. Implementação: a tabela de transição como estrutura de dados e o laço de reconhecimento, com a decisão de representar estados por índices inteiros em vez de referências.

Profundidade: instrumental, com ênfase na correspondência entre a definição matemática e a estrutura de dados que a implementa.

Módulo 4: Não Determinismo e a Construção de Thompson

Autômatos finitos não determinísticos, com e sem transições vazias. Por que o não determinismo é conveniente para a especificação embora inconveniente para a execução. Fecho vazio de um conjunto de estados. Equivalência entre os modelos determinístico e não determinístico, enunciada como teorema. A construção de Thompson, que traduz sistematicamente cada operador de expressão regular em um fragmento de autômato não determinístico, e a razão de a construção ser composicional. Implementação da tradução da árvore de uma expressão regular para o autômato correspondente.

Profundidade: instrumental. Ao final, o estudante implementou a ponte entre a notação do módulo anterior e o modelo de máquina, que é a primeira metade do caminho até o analisador léxico.

Módulo 5: Determinização e Minimização

Conversão do autômato não determinístico em determinístico pela construção de subconjuntos, com o tratamento das transições vazias e a discussão do crescimento exponencial do número de estados no pior caso, contrastado com o comportamento típico. Estados inalcançáveis e sua eliminação. Equivalência e distinguibilidade de estados. Minimização pelo algoritmo de particionamento de Moore, com menção ao refinamento de Hopcroft e à sua complexidade. Unicidade do autômato mínimo a menos de isomorfismo, e o que esse resultado permite afirmar sobre equivalência de linguagens. Exportação do autômato para formato de visualização, que passa a ser instrumento de depuração e de demonstração em aula.

Profundidade: instrumental para a determinização e para a minimização de Moore; conceitual para Hopcroft, cuja implementação é opcional e cujo interesse aqui é a análise de complexidade.

Módulo 6: Limites das Linguagens Regulares

O módulo que fecha o eixo regular estabelecendo sua fronteira. Propriedades de fechamento da classe das linguagens regulares sob união, concatenação, fecho, complemento e interseção, com as construções que as demonstram. O lema do bombeamento como consequência do número finito de estados, sua estrutura lógica de jogo entre dois adversários e o uso da forma contrapositiva para provar que uma linguagem não é regular. Aplicação a exemplos canônicos, com destaque para a linguagem dos parênteses balanceados. O teorema de Myhill-Nerode como caracterização alternativa, em tratamento conceitual. A demonstração prática de que o motor de autômatos já construído não consegue reconhecer aninhamento, o que motiva diretamente o modelo do módulo seguinte.

Profundidade: conceitual com exigência de demonstração. O estudante precisa produzir uma prova de não regularidade completa e correta, ainda que sobre linguagens simples.

Módulo 7: Análise Léxica

Consolidação de todo o eixo regular em uma fase de compilador. O papel do analisador léxico no front-end e sua interface com o analisador sintático. Tokens, lexemas, padrões e atributos. A regra do casamento mais longo e a regra de prioridade entre padrões que casam a mesma cadeia, com a distinção entre palavras reservadas e identificadores. Tratamento de espaços em branco, comentários e fim de arquivo. Detecção e recuperação de erros léxicos, com produção de mensagens úteis. Buffers de entrada e o efeito do retrocesso sobre o desempenho. Geradores automáticos de analisadores léxicos, apresentados em termos do que fazem e de como se relacionam com a construção manual estudada. Implementação do analisador léxico da linguagem condutora, reutilizando integralmente o módulo de autômatos já construído.

Profundidade: instrumental e integradora, com fechamento do primeiro ciclo do projeto. Os geradores automáticos recebem tratamento conceitual, não instrumental.

Módulo 8: Gramáticas Livres de Contexto

Subida na hierarquia. Definição formal de gramática livre de contexto, com variáveis, terminais, produções e símbolo inicial. Derivações mais à esquerda e mais à direita, árvores de derivação e a relação entre elas. Ambiguidade: sua definição, por que é um problema para a compilação e as técnicas usuais de eliminação, incluindo a estratificação por precedência e associatividade de operadores. Ambiguidade inerente, em tratamento conceitual. Simplificação de gramáticas com a remoção de símbolos inúteis, produções vazias e produções unitárias. Formas normais de Chomsky e de Greibach, apresentadas pelo que garantem. Escrita da gramática da linguagem condutora, com justificativa das escolhas que a mantêm não ambígua.

Profundidade: instrumental para escrita, transformação e desambiguação de gramáticas; conceitual para as formas normais.

Módulo 9: Autômatos de Pilha

O modelo de máquina correspondente às linguagens livres de contexto. Definição formal do autômato de pilha, com a pilha como memória auxiliar não limitada e as duas convenções de aceitação, por estado final e por pilha vazia. Equivalência entre gramáticas livres de contexto e autômatos de pilha, com a construção que traduz de uma representação à outra. Determinismo e não determinismo neste modelo, e o fato central de que, ao contrário do caso regular, os dois não são equivalentes — resultado que explica por que a análise sintática prática se restringe a subclasses determinísticas. Lema do bombeamento para linguagens livres de contexto e propriedades de fechamento da classe. Retomada da hierarquia de Chomsky, agora com dois níveis percorridos, e panorama dos níveis restantes, com menção à máquina de Turing e à indecidibilidade.

Profundidade: conceitual, com formalização rigorosa mas sem exigência de implementação do modelo abstrato. A implementação correspondente vem no módulo seguinte, na forma concreta do analisador sintático.

Módulo 10: Análise Sintática Descendente

Do modelo abstrato ao analisador real. A análise sintática como construção da árvore de derivação, e a estratégia descendente como derivação mais à esquerda guiada pela entrada. Recursão à esquerda e sua eliminação; fatoração à esquerda. Conjuntos de primeiros e de seguidores, com os algoritmos de cálculo. A condição LL(1) e a construção da tabela de análise, com a leitura dos conflitos como diagnóstico da gramática. Analisador descendente recursivo, com uma função por variável da gramática, e a correspondência entre a estrutura do código e a estrutura da gramática. Analisador dirigido por tabela com pilha explícita, e a comparação entre as duas realizações. Recuperação de erros sintáticos em modo pânico e em nível de frase, com produção de mensagens que apontem o ponto provável do erro. Construção da árvore sintática abstrata como saída da fase. Implementação do analisador sintático da linguagem condutora.

Profundidade: instrumental e aprofundada. É o módulo mais denso do eixo sintático e o segundo grande marco de implementação do semestre.

Módulo 11: Análise Sintática Ascendente

A alternativa dominante nos compiladores de produção. A estratégia ascendente como redução da entrada ao símbolo inicial, com as operações de deslocamento e redução e o papel da pilha de estados. Itens, autômato de itens e conjunto canônico. Os métodos LR(0), SLR(1), LALR(1) e LR(1) canônico, apresentados como uma escala crescente de poder e custo, com a explicação de qual conflito cada nível resolve. Conflitos de deslocamento-redução e de redução-redução, sua leitura e as estratégias de resolução, incluindo declarações de precedência. Comparação fundamentada entre as famílias descendente e ascendente quanto a poder expressivo, legibilidade do código, qualidade das mensagens de erro e esforço de manutenção. Geradores de analisadores sintáticos, com a leitura dos relatórios de conflito que produzem.

Profundidade: conceitual com exercício de traçado manual. O estudante constrói tabelas para gramáticas pequenas e interpreta conflitos, mas não implementa um gerador; o objetivo é a capacidade de decisão informada e a leitura de ferramentas.

Módulo 12: Análise Semântica

O que a gramática não captura. A distinção entre correção sintática e correção semântica, com exemplos de programas sintaticamente válidos e semanticamente impossíveis. Tabela de símbolos: informação armazenada, estruturas de dados adequadas e operações de inserção e consulta. Escopos aninhados, regras de visibilidade e as estratégias de implementação por pilha de tabelas ou por tabela única com encadeamento. Tradução dirigida por sintaxe, com atributos sintetizados e herdados, gramáticas de atributos e esquemas de tradução. Ordem de avaliação e dependências entre atributos. Verificação de tipos: sistema de tipos, regras de inferência, equivalência de tipos e conversões implícitas. Percursos sobre a árvore sintática abstrata como forma de organizar as verificações. Implementação da tabela de símbolos e das verificações semânticas da linguagem condutora, incluindo a checagem de que cada padrão referenciado foi declarado e de que as comparações são feitas entre operandos compatíveis.

Profundidade: instrumental para tabela de símbolos e verificações; conceitual aprofundado para gramáticas de atributos, com implementação restrita ao esquema efetivamente utilizado no projeto.

Módulo 13: Representações Intermediárias e Ambientes de Execução

A ponte entre análise e síntese. Por que compiladores usam representações intermediárias, e o argumento de reaproveitamento entre linguagens de origem e arquiteturas de destino. Formas usuais: árvore sintática abstrata, notação pós-fixada, código de três endereços com suas variantes de quádruplas e triplas, e menção à atribuição única estática. Tradução de expressões, comandos condicionais e laços para código de três endereços, com o tratamento de rótulos e desvios. Ambientes de execução: organização da memória do programa em execução, com a divisão entre código, dados estáticos, pilha e área de alocação dinâmica. Registros de ativação, sua composição e o protocolo de chamada e retorno. Escopo estático e dinâmico em tempo de execução, e cadeias de acesso e de controle. Gerência de memória, com alocação explícita e panorama da coleta automática de lixo. Definição do formato do objeto produzido pelo compilador da linguagem condutora e do modelo de execução da sua máquina virtual.

Profundidade: instrumental para as representações efetivamente usadas no projeto; conceitual para registros de ativação e coleta de lixo, cuja relevância aqui é o repertório para linguagens com procedimentos.

Módulo 14: Geração de Código

A síntese propriamente dita. O problema da geração de código e seus três subproblemas clássicos: seleção de instruções, alocação de registradores e ordenação da avaliação. Máquinas de pilha e máquinas de registradores como modelos de destino, com a discussão do que cada uma facilita e dificulta. Projeto de um conjunto de instruções de máquina de pilha adequado à linguagem condutora, com as instruções de carga, comparação, combinação lógica e emissão de resultado. Geração de código a partir da árvore sintática abstrata por percurso, com o tratamento de expressões aninhadas e de curto-circuito em operadores lógicos. Alocação de registradores, apresentada pelo modelo de coloração de grafo em tratamento conceitual. Endereçamento e resolução de referências. O caso particular e didaticamente central deste projeto: a emissão dos autômatos determinísticos como tabelas de transição no próprio objeto, de modo que o código gerado contenha, ele mesmo, as máquinas estudadas na primeira metade do curso.

Profundidade: instrumental para a máquina de pilha e para a emissão das tabelas; conceitual para alocação de registradores e para arquiteturas reais de destino.

Módulo 15: Otimização e Integração Final

Fechamento do compilador e do semestre. Blocos básicos e grafo de fluxo de controle, com o algoritmo de identificação de líderes. Otimizações locais: dobramento de constantes, propagação de cópias, eliminação de subexpressões comuns e eliminação de código morto. Panorama das otimizações globais e do papel da análise de fluxo de dados, com a noção de solução por ponto fixo. O compromisso entre tempo de compilação, tempo de execução e preservação da semântica, e a exigência de que toda transformação seja conservadora. Integração final do artefato condutor: a execução ponta a ponta sobre entrada real, com o casamento mais longo entre padrões concorrentes, a ligação de variáveis de casamento, a avaliação das condições das regras e a execução das ações. Tratamento de erros ao longo de todas as fases e a qualidade das mensagens como atributo de projeto. Retrospectiva da disciplina percorrendo o caminho da expressão regular até o programa executável, e panorama de temas adjacentes para estudo posterior, entre eles compilação just-in-time, máquinas virtuais de linguagens de uso corrente e infraestruturas modernas de compilação.

Profundidade: instrumental para blocos básicos e otimizações locais; panorâmica para análise de fluxo de dados e otimização global. O peso do módulo recai sobre a integração e sobre o fechamento conceitual.

Sobre a distribuição entre os dois eixos. Os seis primeiros módulos concentram a teoria de linguagens regulares e autômatos finitos, e só no sétimo aparece a primeira fase completa de um compilador. Essa escolha é deliberada e responde ao risco descrito na abertura. A alternativa — introduzir o analisador léxico no segundo módulo e tratar os autômatos como detalhe de implementação — antecipa a gratificação e sacrifica exatamente aquilo que o título da disciplina promete. A construção incremental do motor de autômatos ao longo dos módulos dois a seis garante que cada resultado teórico seja imediatamente exercitado em código, de modo que a teoria não fique represada: o estudante não espera seis módulos para programar, apenas para chamar o que programou de analisador léxico.

Bibliografia Básica

LOUDEN, Kenneth C. Compiladores: princípios e práticas. São Paulo: Cengage Learning, 2004.

BARBOSA, Cynthia da S. Compiladores. Porto Alegre: SAGAH, 2021.

NETO, João José. Introdução à compilação. 1. ed. Rio de Janeiro: LTC, 1987.

Bibliografia Complementar

AHO, Alfred V. Compiladores: princípios, técnicas e ferramentas. 2. ed. São Paulo: Pearson Education do Brasil, 2008.

SANTOS, Pedro R.; LANGLOIS, Thibault. Compiladores — da teoria à prática. Rio de Janeiro: Grupo GEN, 2018.

SOUSA, Carlos E. B.; NASCIMENTO, Leonardo B. G.; MARTINS, Rafael L. e outros. Linguagens formais e automáticas. Porto Alegre: Grupo A, 2021.

MENEZES, Paulo B. Linguagens formais e autômatos. v. 3. 6. ed. Porto Alegre: Grupo A, 2011.

HUMBERT, Georges L. H. e outros. Linguagens formais e autômatos. 6. ed. Porto Alegre: Grupo A, 2011.

As duas listas acima reproduzem integralmente a bibliografia registrada no projeto pedagógico do curso, sem acréscimos. A obra de Louden sustenta a maior parte do percurso de compilação, e a de Menezes cobre o eixo de linguagens formais com o rigor exigido nos módulos dois a nove. A obra de Aho, embora listada como complementar, é a referência clássica da área e serve de aprofundamento em praticamente todos os módulos.