LRM Prof. Mantovani ← Aulas da disciplina
Semana 2 · Aula 2 de 14

Linguagens, gramáticas e estrutura do compilador

Os níveis de abstração entre o problema humano e o hardware, a organização do compilador em front-end e back-end ligados por uma representação intermediária, e a hierarquia de Chomsky que classifica as linguagens formais e justifica os reconhecedores de cada fase.

📚 Compiladores📝 mini-quiz ao final
Objetivos da aula

O que você vai aprender

1

Relacionar níveis de abstração e o papel do compilador como ponte.

2

Separar responsabilidades de front-end e back-end e justificar a economia m+n.

3

Posicionar as linguagens na hierarquia de Chomsky e entender por que isso importa.

4

Conectar cada nível da hierarquia a uma fase do compilador.

1 · Motivação

Por que linguagens formais?

Para construir um compilador correto, precisamos de uma forma precisa de descrever "o que é um programa válido". Vaguezas em português não bastam — precisamos de matemática.

As linguagens formais e as gramáticas dão essa precisão. Elas permitem dizer, sem ambiguidade, quais sequências de símbolos pertencem à linguagem e quais não.

🔑
Toda a engenharia de compiladores repousa sobre teoria de linguagens formais. Esta aula constrói esse alicerce.
2 · Mapa

O que veremos nesta aula

AbstraçãoFront/back-endLinguagem formalHierarquia de Chomsky
  • As camadas que separam o humano do hardware.
  • A arquitetura em duas pontas e a economia que ela gera.
  • O conceito formal de alfabeto, cadeia e linguagem.
  • Os quatro níveis de Chomsky e seu papel no compilador.
3 · Definição

Alfabeto, cadeia e linguagem

Alfabeto (Σ). Conjunto finito de símbolos.
Cadeia. Sequência finita de símbolos do alfabeto.
Linguagem. Conjunto (possivelmente infinito) de cadeias sobre um alfabeto.

Por exemplo, com Σ = {a, b}, a cadeia "abba" é válida, e a linguagem "todas as cadeias com número par de a" é um subconjunto de todas as cadeias possíveis.

4 · Aprofundamento

Dos transistores às linguagens

Programar é trabalhar em camadas de abstração. Cada camada esconde a complexidade da camada abaixo. O compilador é a ponte entre o nível em que o humano pensa e o nível que a máquina executa.

Alto nívelAssemblyCódigo de máquinaHardware
🔑
Quanto mais alto o nível, mais perto do problema humano e mais longe do hardware. O compilador "desce" o programa por essas camadas.
5 · Exemplo

Uma gramática descreve uma linguagem

Uma gramática é um conjunto de regras que gera as cadeias de uma linguagem. Veja uma gramática mínima:

// gera cadeias como ab, aabb, aaabbb... S → a S b | a b

Aplicando as regras repetidamente, geramos "ab", depois "aabb", depois "aaabbb", e assim por diante. Essa é a linguagem a^n b^n, com n maior ou igual a 1.

6 · Interativo

Passo a passo: derivando uma cadeia

Passo 1
Começamos no símbolo inicial: S.
Passo 2
Aplicamos S → a S b, obtendo: a S b.
Passo 3
Aplicamos S → a b no S do meio, obtendo: a a b b.
Passo 4
Não há mais não-terminais: a cadeia "aabb" pertence à linguagem.
7 · Definição

Front-end e back-end

Front-end. Parte do compilador que depende da linguagem-fonte: análise léxica, sintática e semântica. Produz a representação intermediária.
Back-end. Parte que depende da máquina-alvo: otimização e geração de código. Consome a representação intermediária.
8 · Aprofundamento

A economia da arquitetura em duas pontas

Separar o compilador em front-end e back-end traz uma vantagem prática enorme. Sem essa separação, suportar m linguagens em n máquinas exigiria m×n compiladores distintos.

Reaproveitamento. Com uma representação intermediária comum, escrevem-se apenas m front-ends + n back-ends. É exatamente a ideia do LLVM, que permite combinar qualquer linguagem suportada com qualquer arquitetura suportada.
9 · Analogia

O tradutor de plantão

🔧 Analogia
Imagine uma ONU com m idiomas. Em vez de contratar tradutores para cada par de idiomas (m×m combinações), todos traduzem de e para um idioma-pivô (digamos, inglês). Bastam m tradutores "para o inglês" e m "do inglês". A representação intermediária do compilador é esse idioma-pivô.
10 · Comparação

Front-end × back-end

Front-endBack-end
Análise léxica, sintática e semânticaOtimização e geração de código
Produz a representação intermediáriaConsome a representação intermediária
Depende da linguagem-fonteDepende do processador-alvo
Reaproveitável entre máquinasReaproveitável entre linguagens
11 · Fluxo

A hierarquia de Chomsky em cascata

Os quatro tipos de Chomsky encaixam-se um dentro do outro: toda linguagem regular é livre de contexto, toda livre de contexto é sensível ao contexto, e assim por diante.

Tipo 0
Irrestrita
Tipo 1
Sensível
Tipo 2
Livre de ctx.
Tipo 3
Regular
12 · Aprofundamento

A hierarquia de Chomsky

Noam Chomsky classificou as linguagens formais em quatro tipos, do mais geral ao mais restrito. Cada tipo tem um reconhecedor de poder correspondente:

TipoLinguagemReconhecedorNo compilador
3RegularAutômato finitoAnálise léxica (tokens)
2Livre de contextoAutômato com pilhaAnálise sintática (estrutura)
1Sensível ao contextoAutômato linearmente limitadoAspectos da análise semântica
0IrrestritaMáquina de TuringComputação geral
13 · Verifique

Verifique você mesmo: qual nível?

Parênteses balanceados, como ((())), exigem no mínimo qual nível da hierarquia?

Contar aninhamento arbitrário exige memória ilimitada (uma pilha). Um autômato finito (tipo 3) não consegue; é preciso o autômato com pilha do tipo 2.
14 · Caso prático

Por que cada fase usa um nível

A escolha do reconhecedor mais simples possível por fase não é estética: é eficiência.

💡
Usamos expressões regulares (tipo 3) para tokens porque são rápidas de reconhecer. Usamos gramáticas livres de contexto (tipo 2) para a sintaxe porque elas capturam aninhamento, o que regex não consegue. Cada nível recebe o reconhecedor mais barato que dá conta.
15 · Erros comuns

Enganos sobre a hierarquia

⚠️
Cuidado. Um erro comum é achar que expressões regulares podem casar parênteses balanceados ou tags HTML aninhadas. Não podem: isso exige contagem ilimitada, fora do alcance das linguagens regulares.

Outro engano: pensar que "tipo 0" é o mais restrito. É o contrário — tipo 0 é o mais geral (irrestrito) e tipo 3 é o mais restrito (regular).

16 · Boas práticas

Ferramenta certa para cada nível

Dica. Quando precisar reconhecer algo aninhado (expressões, blocos, JSON), não force uma expressão regular: use uma gramática e um parser. Regex é ideal para padrões "planos" como números, identificadores e datas.
17 · Revelar

Reflita: e a semântica?

Se a sintaxe é livre de contexto (tipo 2), por que não basta uma GLC para todo o programa?
Porque regras como "toda variável deve ser declarada antes de usada" dependem do contexto — do que apareceu antes em outro ponto do programa. Isso é sensível ao contexto (tipo 1) e fica a cargo da análise semântica, não da GLC pura. A GLC cuida da estrutura; a semântica cuida dessas restrições contextuais.
18 · Flashcards

Termos-chave da aula

Linguagem regularvirar
Tipo 3; reconhecida por autômato finito; usada na análise léxica.
Livre de contextovirar
Tipo 2; reconhecida por autômato com pilha; usada na análise sintática.
Alfabetovirar
Conjunto finito de símbolos (Σ) sobre o qual se formam as cadeias.
Representação intermediáriavirar
Linguagem-pivô entre front-end e back-end, independente da máquina.
19 · Conexões

Onde isto se encaixa no curso

Esta aula fundamenta tudo o que vem depois:

  • Tipo 3 (regular) → aulas 3 e 4: ER e autômatos para tokens.
  • Tipo 2 (livre de contexto) → aulas 5 a 7: GLC, parsing e LL(1).
  • Tipo 1 (sensível ao contexto) → aulas 8 e 9: análise semântica.
  • A arquitetura front/back-end → aula 10: representação intermediária.
20 · Síntese

Resumo visual

🔑
O compilador faz o programa descer pelas camadas de abstração. Front-end depende da linguagem; back-end da máquina; uma RI comum os liga. A hierarquia de Chomsky dá o reconhecedor de cada fase: regular→léxico, livre de contexto→sintaxe.
Mão na massa · colaborativo

Atividade em grupo · Classificando construções

Em duplas, classifiquem construções de uma linguagem na hierarquia de Chomsky.

⏱️ 20 min👥 duplas🧩 discussão dirigida

Roteiro

  1. Para cada item, decidam o nível mínimo necessário: identificador, número, expressão aninhada com parênteses, "toda variável deve ser declarada antes do uso".
  2. Justifiquem por que um autômato finito não basta para parênteses balanceados.
  3. Relacionem cada item à fase do compilador correspondente.
  4. Apresentem a tabela final ao restante da turma.
Defensor do léxicoargumenta o que cabe em regex
Defensor da sintaxeargumenta o que exige GLC/contexto
📤 Entrega: Tabela com 4 construções classificadas e justificadas.
Teste seu conhecimento

Mini-quiz · Aula 2

20 questões sobre esta aula. Escolha e veja a explicação na hora.

0/20

📌 Resumo — leve isto para a prova