(vale 1,0 ponto) A notação tradicional para expressões aritméticas, que representa uma operação binária na forma x + y, ou seja, com o operador entre seus dois operandos, é conhecida como notação infixada. Uma notação alternativa para esse tipo de expressão é a notação pré-fixada, na qual o operador é expresso antes de seus operandos, como por exemplo, + x y. Outra notação alternativa é a notação pós-fixada, na qual o operador é expresso após seus operandos, como por exemplo, x y +. O atrativo das notações pré-fixada e pós-fixada é que elas dispensam o uso de parênteses ao adotar a noção de pilha para a representação das expressões. Analise as assertivas a seguir, considerando a gramática livre de contexto G.
G = ({A, E, T, F}, {a, b, c, d, e, f, =, +, -, *, /}, P, A)
P = {A → F=E
E → E+T | E-T | T
T → T*F | T/F | F
F → a | b | c | d | e | f}
Quais das assertivas apresentadas estão corretas?
a. apenas as assertivas I e II.
b. apenas as assertivas I e III.
c. apenas as assertivas II e III.
d. apenas as assertivas II e IV.
e. apenas as assertivas III e IV.
(vale 1,0 ponto) Os principais requisitos impostos a geradores de código objeto são os seguintes: a) o código gerado deve ser correto e de alta qualidade; b) o código deve fazer uso efetivo dos recursos da máquina e; c) o código gerado deve executar eficientemente. O problema de gerar código ótimo é insolúvel (indecidível) como tantos outros. Na prática, devemos contentar-nos com técnicas heurísticas que geram bom código (não necessariamente ótimo). Diante do exposto, o código objeto apresentado a seguir é equivalente a qual comando de atribuição.
LOAD x, R0
COPY R0, R1
LOAD y, R2
ADD R2, R0
SUB R1, R2
COPY R0, R1
DIV R1, R2
SUB R2, R0
ADD R2, R0
STORE R0, z
a. z = (y - x) / (x + y) + (y - x) / (x + y) - (x + y)
b. z = (x + y) - (y - x) / (x + y) + (y - x) / (x + y)
c. z = (x + y) - (y - x) / (x + y) + (x + y) / (y - x)
d. z = (x + y) - (x + y) / (y - x) + (y - x) / (x + y)
e. z = (x + y) / (y - x) + (y - x) / (x + y) - (x + y)
(vale 1,0 ponto) A geração de código intermediário é a transformação da árvore de derivação em um segmento de código. Esse código pode, eventualmente, ser o código objeto final, mas, na maioria das vezes, constitui-se num código intermediário, pois a tradução de código fonte para objeto em mais de um passo apresenta algumas vantagens. Existem vários tipos de código intermediário, como por exemplo, as representações gráficas por meio de árvores e grafo de sintaxe. Uma árvore de sintaxe é uma forma condensada de árvore de derivação na qual somente os operandos da linguagem aparecem como folhas; os operadores constituem nós interiores da árvore. Outra simplificação da árvore de sintaxe é que cadeias de produções simples (por exemplo, A → B, B → C) são eliminadas. Um grafo de sintaxe, além de incluir as simplificações da árvore de sintaxe, faz a fatoração das subexpressões comuns, eliminando-as. Analise as assertivas a seguir, considerando a gramática livre de contexto G.
G = ({A, E, T, F}, {a, b, c, d, e, f, =, +, -, *, /}, P, A)
P = {A → F=E
E → T+E | T-E | T
T → F*T | F/T | F
F → a | b | c | d | e | f}
Quais das assertivas apresentadas estão corretas?
a. apenas as assertivas I e II.
b. apenas as assertivas I e III.
c. apenas as assertivas II e III.
d. apenas as assertivas II e IV.
e. apenas as assertivas III e IV.
(vale 1,0 ponto) Considere o seguinte programa escrito na sintaxe C:
void xpto(int a, int b, int c)
{
a = b * c;
b = a + c;
}
void main()
{
int x;
int y;
scanf("%d", &x);
scanf("%d", &y);
xpto(x, y, x + 2);
printf("%d", x);
printf("%d", y);
}
Com base no programa apresentado, avalie as asserções a seguir.
A respeito dessas asserções, assinale a alternativa correta.
a. apenas as assertivas I e II.
b. apenas as assertivas I e III.
c. apenas as assertivas II e III.
d. apenas as assertivas II e IV.
e. apenas as assertivas III e IV.
(vale 1,0 ponto) Desenvolva um programa em Simpletron Machine Language, que verifique se o número fornecido pelo usuário é um número primo. Caso o valor fornecido pelo usuário seja um número primo, o programa deverá apresentar como resposta o valor 1. Caso o valor fornecido pelo usuário não seja um número primo, o programa deverá apresentar como resposta o valor 0. E caso o usuário forneça um valor inválido, o programa deverá apresentar como resposta o valor -1.
Mais informações sobre números primos na Wikipédia.
Posição | Palavra | Instrução |
---|---|---|
00 | +1020 | read N |
01 | +2020 | load N |
02 | +4114 | branch negative to 14 |
03 | +4214 | branch zero to 14 |
04 | +3122 | subtract 1 |
05 | +2121 | store D |
06 | +3122 | subtract 1 |
07 | +4216 | branch zero to 16 |
08 | +4118 | branch negative to 18 |
09 | +2020 | load N |
10 | +3421 | module D |
11 | +4218 | branch zero to 18 |
12 | +2021 | load D |
13 | +4004 | branch to 04 |
14 | +1123 | write -1 |
15 | +4019 | branch to 19 |
16 | +1122 | write 1 |
17 | +4019 | branch to 19 |
18 | +1124 | write 0 |
19 | +4300 | halt |
20 | +0000 | variable N |
21 | +0000 | variable D |
22 | +0001 | constant 1 |
23 | -0001 | constant -1 |
24 | +0000 | constant 0 |
Welcome to Simpletron!
(vale 1,0 ponto) A fase de otimização do código intermediário vem logo após a fase de geração desse código e tem por objetivo tornar o código intermediário mais apropriado para a produção de código objeto (código de máquina) eficiente, tanto em relação ao tamanho como ao tempo de execução. Uma das técnicas de otimização de código intermediário consiste em identificar segmentos sequencias do programa, chamados blocos básicos, e representá-los através de grafos dirigidos e submetê-los a um processo de otimização. Apresente o código de três endereços otimizado da seguinte sequência de comandos, sobre a gramática livre de contexto G.
x = (a * b) / (c + e - f);
y = d / a * b - (c + e);
z = d / a * (e - f);
G = ({A, E, T, V, F}, {a, b, c, d, e, f, x, y, z, =, +, -, *, /, (, )}, P, A)
P = {A → F=E
E → T+E | T-E | T
T → V*T | V/T | V
V → (E) | F
F → a | b | c | d | e | f | x | y | z}
oper | arg1 | arg2 | result | |
---|---|---|---|---|
(0) | * | a | b | T1 |
(1) | - | e | f | T2 |
(2) | + | c | T2 | T3 |
(3) | / | T1 | T3 | T4 |
(4) | = | T4 | x | |
(5) | / | d | T1 | T5 |
(6) | + | c | e | T6 |
(7) | - | T5 | T6 | T7 |
(8) | = | T7 | y | |
(9) | * | a | T2 | T8 |
(10) | / | d | T8 | T9 |
(11) | = | T9 | z |
(vale 1,0 ponto) Apresente o código objeto resultante do código de três endereços otimizado obtido na Questão 06.
LOAD a, R0 // R0 = a
LOAD b, R1 // R1 = b
MUL R1, R0 // R0 = R0 * R1 (a * b)
COPY R0, R1 // R1 = R0 (a * b)
LOAD e, R2 // R2 = e
LOAD f, R3 // R3 = f
SUB R3, R2 // R2 = R2 - R3 (e - f)
LOAD c, R3 // R3 = c
ADD R2, R3 // R3 = R3 + R2 (c + (e - f))
DIV R3, R0 // R0 = R0 / R3 ((a * b) / (c + (e - f)))
STORE R0, x
LOAD d, R0 // R0 = d
DIV R1, R0 // R0 = R0 / R1 (d / (a * b))
LOAD c, R1 // R1 = c
LOAD e, R3 // R3 = e
ADD R3, R1 // R1 = R1 + R3 (c + e)
SUB R1, R0 // R0 = R0 - R1 ((d / (a * b)) - (c + e))
STORE R0, y
LOAD a, R0 // R0 = a
MUL R2, R0 // R0 = R0 * R2 (a * (e - f))
LOAD d, R1 // R1 = d
DIV R0, R1 // R1 = R1 / R0 (d / (a * (e - f)))
STORE R1, z