Desenvolva um programa em Simpletron Machine Language, que apresente o Máximo Divisor Comum (MDC) entre dois números. Por exemplo, caso os valores fornecidos pelo usuário sejam 18 e 60, o programa deverá apresentar como resposta o valor 6. Caso o usuário forneça valores inválidos (menores ou iguais a zero), o programa deverá apresentar como resposta o valor -1.
Mais informações sobre o Máximo Divisor Comum em Wikipédia.
Posição | Palavra | Instrução |
---|---|---|
00 | +1021 | read A |
01 | +2021 | load A |
02 | +4117 | branch negative to 17 |
03 | +4217 | branch zero to 17 |
04 | +1022 | read B |
05 | +2022 | load B |
06 | +4117 | branch negative to 17 |
07 | +4217 | branch zero to 17 |
08 | +2021 | load A |
09 | +3422 | module B |
10 | +2123 | store C |
11 | +2022 | load B |
12 | +2121 | store A |
13 | +2023 | load C |
14 | +2122 | store B |
15 | +4219 | branch zero to 19 |
16 | +4008 | branch to 08 |
17 | +1124 | write -1 |
18 | +4020 | branch to 20 |
19 | +1121 | write A |
20 | +4300 | halt |
21 | +0000 | variable A |
22 | +0000 | variable B |
23 | +0000 | variable C |
24 | -0001 | constant -1 |
Welcome to Simpletron!
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 → 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.
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 → 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.
Uma representação intermediária do programa fonte pode ser gerada com a transformação da árvore de derivação em um segmento de código. Em relação à etapa de geração de código intermediário do compilador, analise as seguintes assertivas.
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.
Considere o seguinte programa escrito na sintaxe C:
void xpto(int a, int b, int c, int d)
{
a = b * c;
b = a + d;
}
void main()
{
int x, y;
scanf("%d", &x);
scanf("%d", &y);
xpto(x, y, y + 2, x + 3);
printf("%d %d", x, 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.
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 = (c + e - f) / (a * b);
y = (c + e) - d / a * b;
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 → E+T | E-T | T
T → T*V | T/V | V
V → (E) | F
F → a | b | c | d | e | f | x | y | z}
oper | arg1 | arg2 | result | |
---|---|---|---|---|
(0) | + | c | e | T1 |
(1) | - | T1 | f | T2 |
(2) | * | a | b | T3 |
(3) | / | T2 | T3 | T4 |
(4) | = | T4 | x | |
(5) | / | d | a | T5 |
(6) | * | T5 | b | T6 |
(7) | - | T1 | T6 | T7 |
(8) | = | T7 | y | |
(9) | - | e | f | T8 |
(10) | * | T5 | T8 | T9 |
(11) | = | T9 | z |
oper | arg1 | arg2 | result | |
---|---|---|---|---|
(0) | * | a | b | T1 |
(1) | + | c | e | T2 |
(2) | - | T2 | f | T3 |
(3) | / | T3 | T1 | T4 |
(4) | = | T4 | x | |
(5) | / | d | a | T5 |
(6) | * | T5 | b | T6 |
(7) | - | T2 | T6 | T7 |
(8) | = | T7 | y | |
(9) | - | e | f | T8 |
(10) | * | T5 | T8 | T9 |
(11) | = | T9 | z |
Apresente o código objeto resultante do código de três endereços otimizado obtido na Questão 06.
Código objeto resultante do código de três endereços, gerado em pós-ordem
LOAD c, R0 // R0 = c
LOAD e, R1 // R1 = e
ADD R1, R0 // R0 = R0 + R1 (c + e)
COPY R0, R1 // R1 = R0 (c + e)
LOAD f, R2 // R2 = f
SUB R2, R1 // R1 = R1 - R2 ((c + e) - f)
LOAD a, R2 // R2 = a
LOAD b, R3 // R3 = b
MUL R3, R2 // R2 = R2 * R3 (a * b)
DIV R2, R1 // R1 = R1 / R2 (((c + e) - f) / (a * b))
STORE R1, x
LOAD d, R1 // R1 = d
LOAD a, R2 // R2 = a
DIV R2, R1 // R1 = R1 / R2 (d / a)
COPY R1, R2 // R2 = R1 (d / a)
MUL R3, R2 // R2 = R2 * R3 ((d / a) * b)
SUB R2, R0 // R0 = R0 - R2 ((c + e) - ((d / a) * b))
STORE R0, y
LOAD e, R0 // R0 = e
LOAD f, R2 // R2 = f
SUB R2, R0 // R0 = R0 - R2 (e - f)
MUL R0, R1 // R1 = R1 * R0 ((d / a) * (e - f))
STORE R1, z
Código objeto resultante do código de três endereços, gerado em pré-ordem
LOAD a, R0 // R0 = a
LOAD b, R1 // R1 = b
MUL R1, R0 // R0 = R0 * R1 (a * b)
LOAD c, R1 // R1 = c
LOAD e, R2 // R2 = e
ADD R2, R1 // R1 = R1 + R2 (c + e)
COPY R1, R2 // R2 = R1 (c + e)
LOAD f, R3 // R3 = f
SUB R3, R2 // R2 = R2 - R3 ((c + e) - f)
DIV R0, R2 // R2 = R2 / R0 (((c + e) - f) / (a * b))
STORE R2, x
LOAD d, R0 // R0 = d
LOAD a, R2 // R2 = a
DIV R2, R0 // R0 = R0 / R2 (d / a)
COPY R0, R2 // R2 = R0 (d / a)
LOAD b, R3 // R3 = b
MUL R3, R2 // R2 = R2 * R3 ((d / a) * b)
SUB R2, R1 // R1 = R1 - R2 ((c + e) - ((d / a) * b))
STORE R1, y
LOAD e, R1 // R1 = e
LOAD f, R2 // R2 = f
SUB R2, R1 // R1 = R1 - R2 (e - f)
MUL R1, R0 // R0 = R0 * R1 ((d / a) * (e - f))
STORE R0, z