(Enade, 2017) Em um compilador, um analisador sintático descendente preditivo pode ser implementado com o auxílio de uma tabela construída a partir de uma gramática livre de contexto. Essa tabela, chamada tabela LL(k), indica a regra de produção a ser aplicada olhando-se o k-ésimo próximo símbolo lido, chamado lookahead(k). Por motivo de eficiência, normalmente busca-se utilizar k = 1. Considere a gramática livre de contexto G = ({X, Y, Z}, {a, b, c, d, e}, P, X), em que P é composto pelas seguintes regras de produção:
P = {X → aZbXY | c
Y → dX | ε
Z → e}Considere, ainda, a seguinte tabela LL(1), construída a partir da gramática G, sendo $ o símbolo que representa o fim da cadeia. Essa tabela possui duas produções distintas na célula (Y, d), gerando, no analisador sintático, uma dúvida na escolha da regra de produção aplicada em determinados momentos da análise.
| a | b | c | d | e | $ | |
|---|---|---|---|---|---|---|
| X | X → aZbXY | X → c | ||||
| Y | Y → dX Y → ε | Y → ε | ||||
| Z | Z → e |
Considerando que o processo de construção dessa tabela LL(1), a partir da gramática G, foi seguido corretamente, a existência de duas regras de produção distintas na célula (Y, d), neste caso específico, resulta:
a. da ausência do símbolo de fim da cadeia ($) nas regras de produção.
b. de um não-determinismo causado por uma ambiguidade na gramática.
c. do uso incorreto do símbolo de cadeia vazia (ε) nas regras de produção.
d. da presença de duas regras de produção com um único terminal no corpo.
e. da presença de duas regras de produção com o mesmo não terminal na cabeça.
(Enade, 2023) É chamado de compilação o processo de conversão do código escrito pelo programador para um arquivo binário que o computador consegue executar. Esse processo é realizado por um programa chamado compilador. Entre as diversas tarefas de um compilador, destaca-se a de identificar os possíveis erros sintáticos e semânticos. Com base nessas informações, considere uma linguagem de programação em que a sintaxe de uma operação aritmética seja dada pela seguinte gramática livre de contexto:
G = ({S, E, T}, {=, ;, +, -, *, /, (, ), a, b}, P, S)
P = {S → T = E; | T = E; S
E → E + E | E - E | E * E | E / E | (E) | T
T → a | b}Inspirado nessa gramática, um profissional submete a seguinte sentença ao compilador dessa linguagem de programação:
a = a / (b - b);
Com base na gramática da linguagem de programação e acerca do processo de análise sintática e semântica da sentença proposta pelo profissional, é correto afirmar que
a. a gramática gera a sentença apresentada, porém o analisador semântico transmitirá uma mensagem de erro.
b. a gramática gera a sentença apresentada e o erro presente na expressão está fora do escopo das análises sintática e semântica.
c. o analisador léxico transmitirá uma mensagem de erro, pois a gramática não gera a sentença apresentada.
d. o analisador semântico transmitirá uma mensagem de erro, pois a gramática não gera a sentença apresentada.
e. a gramática gera a sentença apresentada, porém o analisador léxico transmitirá uma mensagem de erro.
Desenvolva um programa na linguagem de programação SIMPLE, que indique se o número fornecido pelo usuário é um número perfeito. Um número é considerado perfeito se a soma de seus divisores próprios é igual ao próprio número, como por exemplo o número 6, cuja soma de seus divisores próprios (1 + 2 + 3) é igual a 6. Caso o número seja considerado perfeito, o programa deverá retornar 1, caso contrário, deverá retornar 0. Caso o número fornecido pelo usuário seja menor do que 2, o programa deverá retornar -1.
(Enade, 2021) Um compilador é um software que traduz um programa descrito em uma linguagem de alto nível para um programa equivalente em código de máquina para um processador. Em geral, um compilador não produz diretamente o código de máquina, mas sim, um programa em linguagem simbólica (assembly) semanticamente equivalente ao programa em linguagem de alto nível. O programa em linguagem simbólica é, então, traduzido para o programa em linguagem de máquina através de montadores. Para realizar esta tarefa, o compilador executa a análise léxica, sintática e semântica do código-fonte do programa que está sendo executado em linguagem abstrata para depois gerar o código de máquina.
BRANCO, G. A. Jr.; TAMAE, R. Y. Uma breve introdução ao estudo e implementação de compiladores.
Revista Científica Eletrônica de Psicologia. Ano V, n. 08, fev. 2008 (adaptado).
Considerando as informações do texto, avalie as assertivas a seguir.
É correto apenas o que se afirma
a. nas assertivas I e II.
b. nas assertivas I e III.
c. nas assertivas II e III.
d. nas assertivas II e IV.
e. nas assertivas III e IV.
(Poscomp, 2024) No contexto da construção de compiladores, um Esquema de Tradução é um(a):
a. Grafo que relaciona atributos entre regras de produção diferentes de uma gramática livre de contexto.
b. Sequência de ações que descreve informalmente o funcionamento de todas as etapas do compilador.
c. Técnica de recuperação de erros que consiste em obter estruturas de controle semanticamente equivalentes às definidas pelo programador.
d. Forma de análise semântica, que considera o tipo das variáveis dos programas, de forma a evitar erros nos programas gerados.
e. Gramática livre de contexto na qual fragmentos de programas (ações) são inseridos nos lados direitos das regras de produção.
Analisadores de precedência de operadores operam sobre a classe das gramáticas de operadores, ou seja, gramáticas 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. Considerando a tabela de precedência de operadores apresentada a seguir, apresente a sequência de movimentos para o reconhecimento da entrada a * b (c) d.
G = ({A, B, C, D}, {+, *, a, b, c, d, (, )}, P, A)
P = {A → A + B | B
B → B * C | C
C → (A) | D} D → a | b | c | d}| + | * | a..d | ( | ) | $ | |
|---|---|---|---|---|---|---|
| + | < | < | < | < | > | > |
| * | > | > | < | < | > | > |
| a..d | > | > | erro 2 | erro 2 | > | > |
| ( | < | < | < | < | = | erro 1 |
| ) | > | > | erro 2 | erro 2 | > | > |
| $ | < | < | < | < | erro 3 | aceita |
Erros na consulta a matriz:
erro 1 - empilha ) e emite a mensagem: falta de parêntese à direita.
erro 2 - insere + na entrada e emite a mensagem: operador esperado.
erro 3 - descarta ) da entrada e emite a mensagem: parêntese direito ilegal.
Erros na redução do handle:
erro 4 - se + ou * definem um handle, verificar se existem variáveis em ambos os lados do operador. Em caso negativo, executar a redução e emitir a mensagem: falta expressão.
erro 5 - se o par ( ) deve ser reduzido, verificar se existe uma variável entre os parênteses. Em caso negativo, executar a redução e emitir a mensagem: expressão nula entre parênteses.
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;(;a);), considerando a tabela M apresentada a seguir.
| a | ; | ( | ) | $ | |
|---|---|---|---|---|---|
| A | A → a | sinc | A → (B) | sinc | sinc |
| B | B → aD | B → (B)D | sinc | ||
| C | C → ;AD | sinc | |||
| D | D → C | D → ε |