(Poscomp, 2025) Sobre linguagens e gramáticas livres de contexto e autômatos com pilha, analise as assertivas abaixo e assinale V, se verdadeiras, ou F, se falsas.
( ) Em uma gramática livre de contexto, as derivações à esquerda e à direita de uma mesma cadeia podem resultar em diferentes árvores de derivação.
( ) Uma gramática é dita ambígua se existir ao menos uma cadeia que tenha duas ou mais árvores de derivação distintas.
( ) A classe LL(1) não aceita linguagens com produções que apresentem recursões diretas à esquerda (ex. L→La), mas aceita linguagens com recursões indiretas (ex. L→Ra, R→Lb).
( ) Toda linguagem livre de contexto pode ser aceita por um autômato com pilha, desde que ele use o critério de aceitação por pilha vazia.
( ) A simplificação de uma gramática pode alterar a linguagem gerada, pois remove símbolos inúteis e símbolos inacessíveis.
A ordem correta de preenchimento dos parênteses, de cima para baixo, é:
a. V – V – F – V – F.
b. F – V – F – F – F.
c. V – F – V – F – V.
d. V – F – F – V – V.
e. F – F – V – F – V.
(Poscomp, 2023) Seja a seguinte linguagem, onde ε representa a string vazio e $ representa um marcador de fim de entrada.
G = ({S, A, B, C, D}, {a, b, c, d, e}, P, A)
P = {S → ABCD
A → aA | ε
B → bB | ε
C → cC | e
D → d | ε}É correto afirmar que:
a. O conjunto FIRST(A) é igual ao conjunto FIRST(B).
b. O conjunto FIRST(D) é igual ao conjunto FIRST(S).
c. O conjunto FIRST(C) é igual ao conjunto FOLLOW(B).
d. O conjunto FOLLOW(B) é igual ao conjunto FOLLOW(S).
e. O conjunto FOLLOW(A) é igual a FOLLOW(D).
Analisadores de precedência de operadores operam sobre a classe das gramáticas de operadores, ou seja, gramáticas em que os não-terminais aparecem sempre separados por símbolos terminais e que as produções não derivam a palavra vazia. A análise de precedência de operadores é bastante eficiente e é aplicada, principalmente, no reconhecimento de expressões, como expressões aritméticas e lógicas. Apresente a sequência de movimentos da entrada a+b*c/d-e, considerando a tabela de precedência de operadores apresentada a seguir.
G = ({A, B, C}, {a, b, c, d, e, +, -, *, /}, P, A)
P = {A → A + B | A - B | B
B → B * C | B / C | C
C → a | b | c | d | e}| + | - | * | / | a ... b | $ | |
|---|---|---|---|---|---|---|
| + | > | > | < | < | < | > |
| - | > | > | < | < | < | > |
| * | > | > | < | < | < | > |
| / | > | > | < | < | < | > |
| a ... b | > | > | > | > | > | |
| $ | < | < | < | < | < | aceita |
A Tabela de Símbolos é uma estrutura de dados essencial na arquitetura de um compilador, atuando como o "banco de dados" que conecta as diversas fases da compilação (análise léxica, sintática, semântica e geração de código). Ela armazena informações sobre os identificadores encontrados no código-fonte.
Com base no propósito e no conteúdo típico dessa estrutura de dados, assinale a alternativa que apresenta uma informação que NÃO é armazenada na Tabela de Símbolos.
a. O tipo de dado (ex.: inteiro, real, ponteiro) e o escopo (nível de aninhamento ou bloco) de uma variável declarada no código-fonte.
b. O deslocamento de memória (offset) de uma variável local em relação ao ponteiro base da pilha de execução, utilizado para a geração de código de máquina.
c. O valor dinâmico (estado atual) armazenado em uma variável durante a execução do programa compilado.
d. A assinatura de uma função ou procedimento, incluindo o tipo de retorno, a quantidade de parâmetros e os tipos de dados de cada parâmetro formal.
e. A categoria do identificador (ex.: variável simples, vetor, função, tipo definido pelo usuário) e atributos especiais (ex.: const, volatile, modo de passagem de parâmetro por referência).
A compilação de um programa de alto nível para código de máquina é um processo complexo que envolve múltiplas fases inter-relacionadas. Cada fase possui responsabilidades bem definidas e depende da saída da fase anterior para executar sua tarefa corretamente. A ordem em que essas fases são executadas reflete a progressão lógica desde a compreensão do texto-fonte até a produção do executável final. Assinale a alternativa que apresenta a ordem CORRETA das fases de um compilador, da primeira à última etapa executada.
a. Análise Sintática → Análise Léxica → Análise Semântica → Geração de Código Intermediário → Alocação de Variáveis → Otimização de Código → Geração de Código Objeto.
b. Análise Léxica → Análise Sintática → Análise Semântica → Geração de Código Intermediário → Otimização de Código → Alocação de Variáveis → Geração de Código Objeto.
c. Análise Léxica → Análise Sintática → Geração de Código Intermediário → Análise Semântica → Otimização de Código → Alocação de Variáveis → Geração de Código Objeto.
d. Análise Léxica → Análise Sintática → Análise Semântica → Otimização de Código → Geração de Código Intermediário → Alocação de Variáveis → Geração de Código Objeto.
e. Análise Léxica → Análise Sintática → Análise Semântica → Geração de Código Intermediário → Alocação de Variáveis → Otimização de Código → Geração de Código Objeto.
Desenvolva um programa na linguagem de programação SIMPLE que verifique se o número fornecido pelo usuário pertence à sequência de Fibonacci. A sequência é definida recursivamente por F0 = 0, F1 = 1 e Fn = Fn-1 + Fn-2, para n ≥ 2. Caso o número pertença à sequência de Fibonacci, o programa deverá retornar 1; caso contrário, deverá retornar 0.
Um analisador sintático preditivo sem recursão pode ser construído mantendo uma pilha explicitamente, em vez de implicitamente, via chamadas recursivas. O analisador é dirigido por um programa que considera X, o símbolo no topo da pilha, e a, o símbolo corrente da entrada. Se X é um não-terminal, o analisador escolhe uma produção-X consultando a entrada M[X, a] da tabela M de análise. Por outro lado, ele tenta fazer um casamento entre o terminal X no topo da pilha e o símbolo corrente a da entrada. Apresente a sequência de movimentos, com recuperação de erros em modo pânico, da entrada (a*+b)c*d, considerando a tabela M apresentada a seguir.
| ( | ) | * | + | a ... d | $ | |
|---|---|---|---|---|---|---|
| A | A → CB | sinc | A → CB | sinc | ||
| B | B → ε | B → +CB | B → ε | |||
| C | C → ED | sinc | sinc | C → ED | sinc | |
| D | D → ε | D → *ED | D → ε | D → ε | ||
| E | E → (A) | sinc | sinc | sinc | E → a | ... | d | sinc |