@designliquido/delegua 1.26.1 → 1.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bibliotecas/dialetos/pitugues/primitivas-dicionario.js +3 -3
- package/bibliotecas/dialetos/pitugues/primitivas-dicionario.js.map +1 -1
- package/bibliotecas/dialetos/pitugues/primitivas-numero.js +2 -2
- package/bibliotecas/dialetos/pitugues/primitivas-numero.js.map +1 -1
- package/bibliotecas/dialetos/pitugues/primitivas-texto.js +17 -17
- package/bibliotecas/dialetos/pitugues/primitivas-texto.js.map +1 -1
- package/bibliotecas/dialetos/pitugues/primitivas-vetor.js +13 -13
- package/bibliotecas/dialetos/pitugues/primitivas-vetor.js.map +1 -1
- package/bin/package.json +2 -2
- package/package.json +2 -2
- package/tradutores/tradutor-assembly-x64.d.ts +11 -96
- package/tradutores/tradutor-assembly-x64.d.ts.map +1 -1
- package/tradutores/tradutor-assembly-x64.js +25 -761
- package/tradutores/tradutor-assembly-x64.js.map +1 -1
- package/tradutores/tradutor-javascript.d.ts +1 -1
- package/tradutores/tradutor-javascript.d.ts.map +1 -1
- package/tradutores/tradutor-javascript.js +7 -0
- package/tradutores/tradutor-javascript.js.map +1 -1
- package/tradutores/tradutor-python.d.ts +8 -0
- package/tradutores/tradutor-python.d.ts.map +1 -1
- package/tradutores/tradutor-python.js +35 -4
- package/tradutores/tradutor-python.js.map +1 -1
- package/tradutores/tradutor-reverso-javascript.d.ts.map +1 -1
- package/tradutores/tradutor-reverso-javascript.js +3 -0
- package/tradutores/tradutor-reverso-javascript.js.map +1 -1
- package/tradutores/x64/alocador-registradores.d.ts +29 -0
- package/tradutores/x64/alocador-registradores.d.ts.map +1 -0
- package/tradutores/x64/alocador-registradores.js +192 -0
- package/tradutores/x64/alocador-registradores.js.map +1 -0
- package/tradutores/x64/codegen.d.ts +43 -0
- package/tradutores/x64/codegen.d.ts.map +1 -0
- package/tradutores/x64/codegen.js +416 -0
- package/tradutores/x64/codegen.js.map +1 -0
- package/tradutores/x64/dessa.d.ts +9 -0
- package/tradutores/x64/dessa.d.ts.map +1 -0
- package/tradutores/x64/dessa.js +124 -0
- package/tradutores/x64/dessa.js.map +1 -0
- package/tradutores/x64/dominancia.d.ts +25 -0
- package/tradutores/x64/dominancia.d.ts.map +1 -0
- package/tradutores/x64/dominancia.js +129 -0
- package/tradutores/x64/dominancia.js.map +1 -0
- package/tradutores/x64/ir.d.ts +144 -0
- package/tradutores/x64/ir.d.ts.map +1 -0
- package/tradutores/x64/ir.js +44 -0
- package/tradutores/x64/ir.js.map +1 -0
- package/tradutores/x64/liveness.d.ts +12 -0
- package/tradutores/x64/liveness.d.ts.map +1 -0
- package/tradutores/x64/liveness.js +159 -0
- package/tradutores/x64/liveness.js.map +1 -0
- package/tradutores/x64/lowering.d.ts +7 -0
- package/tradutores/x64/lowering.d.ts.map +1 -0
- package/tradutores/x64/lowering.js +904 -0
- package/tradutores/x64/lowering.js.map +1 -0
- package/tradutores/x64/ssa.d.ts +9 -0
- package/tradutores/x64/ssa.d.ts.map +1 -0
- package/tradutores/x64/ssa.js +170 -0
- package/tradutores/x64/ssa.js.map +1 -0
- package/tradutores/x64/tipos-x64.d.ts +12 -0
- package/tradutores/x64/tipos-x64.d.ts.map +1 -0
- package/tradutores/x64/tipos-x64.js +59 -0
- package/tradutores/x64/tipos-x64.js.map +1 -0
- package/umd/delegua.js +2512 -1001
|
@@ -0,0 +1,904 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoweringX64 = void 0;
|
|
4
|
+
const construtos_1 = require("../../construtos");
|
|
5
|
+
const declaracoes_1 = require("../../declaracoes");
|
|
6
|
+
const tipos_x64_1 = require("./tipos-x64");
|
|
7
|
+
const ir_1 = require("./ir");
|
|
8
|
+
const OPERADORES_BINARIOS = new Set(['+', '-', '*', '/', '%', '<', '>', '<=', '>=', '==', '!=']);
|
|
9
|
+
/**
|
|
10
|
+
* Percorre a AST (declarações e construtos) chamando `visitante` em pré-ordem.
|
|
11
|
+
* `visitante` retorna `false` para podar a recursão num nó (usado para não descer em
|
|
12
|
+
* corpos de função aninhada, que têm escopo próprio e não são suportados aqui).
|
|
13
|
+
*/
|
|
14
|
+
function percorrer(no, visitante) {
|
|
15
|
+
if (!no || typeof no !== 'object')
|
|
16
|
+
return;
|
|
17
|
+
if (Array.isArray(no)) {
|
|
18
|
+
for (const item of no)
|
|
19
|
+
percorrer(item, visitante);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (!visitante(no))
|
|
23
|
+
return;
|
|
24
|
+
const objeto = no;
|
|
25
|
+
const nome = objeto.constructor?.name;
|
|
26
|
+
switch (nome) {
|
|
27
|
+
case 'Bloco':
|
|
28
|
+
percorrer(objeto.declaracoes, visitante);
|
|
29
|
+
break;
|
|
30
|
+
case 'Se': {
|
|
31
|
+
const se = objeto;
|
|
32
|
+
percorrer(se.condicao, visitante);
|
|
33
|
+
percorrer(se.caminhoEntao, visitante);
|
|
34
|
+
if (se.caminhosSeSenao) {
|
|
35
|
+
for (const caminho of se.caminhosSeSenao) {
|
|
36
|
+
percorrer(caminho.condicao, visitante);
|
|
37
|
+
percorrer(caminho.caminho, visitante);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (se.caminhoSenao)
|
|
41
|
+
percorrer(se.caminhoSenao, visitante);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case 'Enquanto': {
|
|
45
|
+
const enquanto = objeto;
|
|
46
|
+
percorrer(enquanto.condicao, visitante);
|
|
47
|
+
percorrer(enquanto.corpo, visitante);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case 'Para': {
|
|
51
|
+
const para = objeto;
|
|
52
|
+
if (para.inicializador)
|
|
53
|
+
percorrer(para.inicializador, visitante);
|
|
54
|
+
percorrer(para.condicao, visitante);
|
|
55
|
+
percorrer(para.incrementar, visitante);
|
|
56
|
+
percorrer(para.corpo, visitante);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case 'ParaCada': {
|
|
60
|
+
const paraCada = objeto;
|
|
61
|
+
percorrer(paraCada.vetorOuDicionario, visitante);
|
|
62
|
+
percorrer(paraCada.corpo, visitante);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case 'Fazer': {
|
|
66
|
+
const fazer = objeto;
|
|
67
|
+
percorrer(fazer.caminhoFazer, visitante);
|
|
68
|
+
percorrer(fazer.condicaoEnquanto, visitante);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case 'Retorna':
|
|
72
|
+
if (objeto.valor)
|
|
73
|
+
percorrer(objeto.valor, visitante);
|
|
74
|
+
break;
|
|
75
|
+
case 'Expressao':
|
|
76
|
+
percorrer(objeto.expressao, visitante);
|
|
77
|
+
break;
|
|
78
|
+
case 'Var':
|
|
79
|
+
if (objeto.inicializador)
|
|
80
|
+
percorrer(objeto.inicializador, visitante);
|
|
81
|
+
break;
|
|
82
|
+
case 'Const':
|
|
83
|
+
percorrer(objeto.inicializador, visitante);
|
|
84
|
+
break;
|
|
85
|
+
case 'Escreva':
|
|
86
|
+
percorrer(objeto.argumentos, visitante);
|
|
87
|
+
break;
|
|
88
|
+
case 'Escolha': {
|
|
89
|
+
const escolha = objeto;
|
|
90
|
+
percorrer(escolha.identificadorOuLiteral, visitante);
|
|
91
|
+
for (const caminho of escolha.caminhos ?? []) {
|
|
92
|
+
percorrer(caminho.condicoes, visitante);
|
|
93
|
+
percorrer(caminho.declaracoes, visitante);
|
|
94
|
+
}
|
|
95
|
+
if (escolha.caminhoPadrao)
|
|
96
|
+
percorrer(escolha.caminhoPadrao.declaracoes, visitante);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
case 'Falhar':
|
|
100
|
+
if (objeto.explicacao)
|
|
101
|
+
percorrer(objeto.explicacao, visitante);
|
|
102
|
+
break;
|
|
103
|
+
case 'Variavel':
|
|
104
|
+
case 'Literal':
|
|
105
|
+
case 'Importar':
|
|
106
|
+
case 'Classe':
|
|
107
|
+
case 'Tente':
|
|
108
|
+
case 'FuncaoConstruto':
|
|
109
|
+
case 'FuncaoDeclaracao':
|
|
110
|
+
break;
|
|
111
|
+
case 'Binario': {
|
|
112
|
+
const binario = objeto;
|
|
113
|
+
percorrer(binario.esquerda, visitante);
|
|
114
|
+
percorrer(binario.direita, visitante);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case 'Unario':
|
|
118
|
+
percorrer(objeto.operando, visitante);
|
|
119
|
+
break;
|
|
120
|
+
case 'Logico': {
|
|
121
|
+
const logico = objeto;
|
|
122
|
+
percorrer(logico.esquerda, visitante);
|
|
123
|
+
percorrer(logico.direita, visitante);
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case 'Vetor':
|
|
127
|
+
percorrer(objeto.elementos, visitante);
|
|
128
|
+
break;
|
|
129
|
+
case 'Chamada': {
|
|
130
|
+
const chamada = objeto;
|
|
131
|
+
percorrer(chamada.entidadeChamada, visitante);
|
|
132
|
+
percorrer(chamada.argumentos, visitante);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'AcessoIndiceVariavel': {
|
|
136
|
+
const acesso = objeto;
|
|
137
|
+
percorrer(acesso.entidadeChamada, visitante);
|
|
138
|
+
percorrer(acesso.indice, visitante);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case 'AtribuicaoPorIndice': {
|
|
142
|
+
const atribuicao = objeto;
|
|
143
|
+
percorrer(atribuicao.objeto, visitante);
|
|
144
|
+
percorrer(atribuicao.indice, visitante);
|
|
145
|
+
percorrer(atribuicao.valor, visitante);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case 'Atribuir': {
|
|
149
|
+
const atribuir = objeto;
|
|
150
|
+
percorrer(atribuir.alvo, visitante);
|
|
151
|
+
if (atribuir.indice)
|
|
152
|
+
percorrer(atribuir.indice, visitante);
|
|
153
|
+
percorrer(atribuir.valor, visitante);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case 'Agrupamento':
|
|
157
|
+
percorrer(objeto.expressao, visitante);
|
|
158
|
+
break;
|
|
159
|
+
case 'DefinirValor': {
|
|
160
|
+
const definirValor = objeto;
|
|
161
|
+
percorrer(definirValor.objeto, visitante);
|
|
162
|
+
percorrer(definirValor.valor, visitante);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case 'AcessoMetodo':
|
|
166
|
+
percorrer(objeto.objeto, visitante);
|
|
167
|
+
break;
|
|
168
|
+
case 'TipoDe':
|
|
169
|
+
percorrer(objeto.valor, visitante);
|
|
170
|
+
break;
|
|
171
|
+
case 'Leia':
|
|
172
|
+
percorrer(objeto.argumentos, visitante);
|
|
173
|
+
break;
|
|
174
|
+
default:
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function coletarReferenciasEDeclaracoes(corpo) {
|
|
179
|
+
const referenciadas = new Set();
|
|
180
|
+
const declaradas = new Set();
|
|
181
|
+
percorrer(corpo, (no) => {
|
|
182
|
+
const objeto = no;
|
|
183
|
+
const nomeClasse = objeto.constructor?.name;
|
|
184
|
+
if (nomeClasse === 'Variavel') {
|
|
185
|
+
referenciadas.add(no.simbolo.lexema);
|
|
186
|
+
}
|
|
187
|
+
else if (nomeClasse === 'Var' || nomeClasse === 'Const') {
|
|
188
|
+
declaradas.add(no.simbolo.lexema);
|
|
189
|
+
}
|
|
190
|
+
if (nomeClasse === 'FuncaoConstruto' || nomeClasse === 'FuncaoDeclaracao')
|
|
191
|
+
return false;
|
|
192
|
+
return true;
|
|
193
|
+
});
|
|
194
|
+
return { referenciadas, declaradas };
|
|
195
|
+
}
|
|
196
|
+
function inferirTipoRetorno(corpo) {
|
|
197
|
+
let encontrado;
|
|
198
|
+
percorrer(corpo, (no) => {
|
|
199
|
+
const objeto = no;
|
|
200
|
+
const nomeClasse = objeto.constructor?.name;
|
|
201
|
+
if (nomeClasse === 'Retorna' && !encontrado) {
|
|
202
|
+
const retorna = no;
|
|
203
|
+
if (retorna.valor?.tipo)
|
|
204
|
+
encontrado = retorna.valor.tipo;
|
|
205
|
+
}
|
|
206
|
+
if (nomeClasse === 'FuncaoConstruto' || nomeClasse === 'FuncaoDeclaracao')
|
|
207
|
+
return false;
|
|
208
|
+
return true;
|
|
209
|
+
});
|
|
210
|
+
return encontrado;
|
|
211
|
+
}
|
|
212
|
+
/** Constrói o IR de uma única função (ou do "principal" implícito) mantendo o bloco atual. */
|
|
213
|
+
class ConstrutorFuncao {
|
|
214
|
+
constructor(nome, ehImplicitaTopo, programa, assinaturas) {
|
|
215
|
+
this.programa = programa;
|
|
216
|
+
this.assinaturas = assinaturas;
|
|
217
|
+
this.encerrado = false;
|
|
218
|
+
this.contadorTemp = 0;
|
|
219
|
+
this.contadorBloco = 0;
|
|
220
|
+
this.locais = new Map();
|
|
221
|
+
this.funcao = (0, ir_1.novaFuncao)(nome, ehImplicitaTopo);
|
|
222
|
+
const entrada = (0, ir_1.novoBloco)('entrada');
|
|
223
|
+
this.funcao.blocos.set('entrada', entrada);
|
|
224
|
+
this.funcao.ordemBlocos.push('entrada');
|
|
225
|
+
this.funcao.blocoEntrada = 'entrada';
|
|
226
|
+
this.blocoAtualId = 'entrada';
|
|
227
|
+
}
|
|
228
|
+
declararLocalEscalar(nome, tipo) {
|
|
229
|
+
this.locais.set(nome, { classe: 'escalar', tipo });
|
|
230
|
+
}
|
|
231
|
+
declararLocalArray(nome, info) {
|
|
232
|
+
this.locais.set(nome, { classe: 'array', tipo: info.tipoElemento });
|
|
233
|
+
this.funcao.arranjosLocais.set(nome, info);
|
|
234
|
+
}
|
|
235
|
+
blocoAtual() {
|
|
236
|
+
return this.funcao.blocos.get(this.blocoAtualId);
|
|
237
|
+
}
|
|
238
|
+
emitir(instrucao) {
|
|
239
|
+
if (this.encerrado)
|
|
240
|
+
return;
|
|
241
|
+
this.blocoAtual().instrucoes.push(instrucao);
|
|
242
|
+
}
|
|
243
|
+
novoTemp() {
|
|
244
|
+
return `%t${this.contadorTemp++}`;
|
|
245
|
+
}
|
|
246
|
+
novoBlocoId() {
|
|
247
|
+
return `bloco_${this.contadorBloco++}`;
|
|
248
|
+
}
|
|
249
|
+
criarBloco() {
|
|
250
|
+
const id = this.novoBlocoId();
|
|
251
|
+
this.funcao.blocos.set(id, (0, ir_1.novoBloco)(id));
|
|
252
|
+
this.funcao.ordemBlocos.push(id);
|
|
253
|
+
return id;
|
|
254
|
+
}
|
|
255
|
+
irPara(id) {
|
|
256
|
+
this.blocoAtualId = id;
|
|
257
|
+
this.encerrado = false;
|
|
258
|
+
}
|
|
259
|
+
terminarCom(terminador) {
|
|
260
|
+
if (this.encerrado)
|
|
261
|
+
return;
|
|
262
|
+
this.blocoAtual().terminador = terminador;
|
|
263
|
+
this.encerrado = true;
|
|
264
|
+
}
|
|
265
|
+
finalizar() {
|
|
266
|
+
if (!this.encerrado) {
|
|
267
|
+
this.terminarCom({ op: 'retorno' });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
resolverEscalar(nome) {
|
|
271
|
+
const local = this.locais.get(nome);
|
|
272
|
+
if (local)
|
|
273
|
+
return local;
|
|
274
|
+
if (this.programa.globaisEscalares.has(nome)) {
|
|
275
|
+
return { classe: 'escalar', tipo: this.programa.globaisEscalares.get(nome) };
|
|
276
|
+
}
|
|
277
|
+
if (this.programa.globaisArranjos.has(nome)) {
|
|
278
|
+
const info = this.programa.globaisArranjos.get(nome);
|
|
279
|
+
return { classe: 'array', tipo: info.tipoElemento };
|
|
280
|
+
}
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
resolverArranjoInfo(nome) {
|
|
284
|
+
const local = this.funcao.arranjosLocais.get(nome);
|
|
285
|
+
if (local)
|
|
286
|
+
return local;
|
|
287
|
+
const global = this.programa.globaisArranjos.get(nome);
|
|
288
|
+
if (global)
|
|
289
|
+
return global;
|
|
290
|
+
throw new Error(`Vetor '${nome}' não declarado.`);
|
|
291
|
+
}
|
|
292
|
+
ehLocalEscalar(nome) {
|
|
293
|
+
const local = this.locais.get(nome);
|
|
294
|
+
return !!local && local.classe === 'escalar';
|
|
295
|
+
}
|
|
296
|
+
lerEscalar(nome) {
|
|
297
|
+
const info = this.resolverEscalar(nome);
|
|
298
|
+
if (!info) {
|
|
299
|
+
throw new Error(`Variável '${nome}' não declarada, não é parâmetro/local desta função, nem uma ` +
|
|
300
|
+
`variável global (do escopo principal) referenciada por alguma função — o ` +
|
|
301
|
+
`tradutor para x64 não suporta capturar variáveis locais de outras funções.`);
|
|
302
|
+
}
|
|
303
|
+
if (info.classe === 'array') {
|
|
304
|
+
throw new Error(`'${nome}' é um vetor; use acesso por índice.`);
|
|
305
|
+
}
|
|
306
|
+
if (this.locais.has(nome)) {
|
|
307
|
+
return (0, ir_1.valorRegistrador)(nome);
|
|
308
|
+
}
|
|
309
|
+
const temp = this.novoTemp();
|
|
310
|
+
this.emitir({ op: 'carregarGlobal', dst: temp, rotulo: nome });
|
|
311
|
+
return (0, ir_1.valorRegistrador)(temp);
|
|
312
|
+
}
|
|
313
|
+
escreverEscalar(nome, valor) {
|
|
314
|
+
const info = this.resolverEscalar(nome);
|
|
315
|
+
if (!info) {
|
|
316
|
+
throw new Error(`Variável '${nome}' não declarada.`);
|
|
317
|
+
}
|
|
318
|
+
if (this.locais.has(nome)) {
|
|
319
|
+
this.emitir({ op: 'copia', dst: nome, src: valor });
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
this.emitir({ op: 'armazenarGlobal', rotulo: nome, valor });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
assinaturaDe(nomeFuncao) {
|
|
326
|
+
const assinatura = this.assinaturas.get(nomeFuncao);
|
|
327
|
+
if (!assinatura) {
|
|
328
|
+
throw new Error(`Função '${nomeFuncao}' não declarada — o tradutor para x64 não suporta chamadas indiretas.`);
|
|
329
|
+
}
|
|
330
|
+
return assinatura;
|
|
331
|
+
}
|
|
332
|
+
literalTexto(valor) {
|
|
333
|
+
for (const [rotulo, texto] of this.programa.literaisTexto) {
|
|
334
|
+
if (texto === valor)
|
|
335
|
+
return rotulo;
|
|
336
|
+
}
|
|
337
|
+
const rotulo = `str_${this.programa.literaisTexto.size}`;
|
|
338
|
+
this.programa.literaisTexto.set(rotulo, valor);
|
|
339
|
+
return rotulo;
|
|
340
|
+
}
|
|
341
|
+
// --- Declarações ---
|
|
342
|
+
lowerBloco(declaracoes) {
|
|
343
|
+
for (const declaracao of declaracoes)
|
|
344
|
+
this.lowerDeclaracao(declaracao);
|
|
345
|
+
}
|
|
346
|
+
lowerDeclaracao(declaracao) {
|
|
347
|
+
const nomeClasse = declaracao.constructor.name;
|
|
348
|
+
switch (nomeClasse) {
|
|
349
|
+
case 'Bloco':
|
|
350
|
+
this.lowerBloco(declaracao.declaracoes);
|
|
351
|
+
return;
|
|
352
|
+
case 'Expressao':
|
|
353
|
+
this.lowerConstruto(declaracao.expressao);
|
|
354
|
+
return;
|
|
355
|
+
case 'Var':
|
|
356
|
+
this.lowerVarOuConst(declaracao, false);
|
|
357
|
+
return;
|
|
358
|
+
case 'Const':
|
|
359
|
+
this.lowerVarOuConst(declaracao, true);
|
|
360
|
+
return;
|
|
361
|
+
case 'Escreva':
|
|
362
|
+
this.lowerEscreva(declaracao);
|
|
363
|
+
return;
|
|
364
|
+
case 'Se':
|
|
365
|
+
this.lowerSe(declaracao);
|
|
366
|
+
return;
|
|
367
|
+
case 'Enquanto':
|
|
368
|
+
this.lowerEnquanto(declaracao);
|
|
369
|
+
return;
|
|
370
|
+
case 'Para':
|
|
371
|
+
this.lowerPara(declaracao);
|
|
372
|
+
return;
|
|
373
|
+
case 'ParaCada':
|
|
374
|
+
this.lowerParaCada(declaracao);
|
|
375
|
+
return;
|
|
376
|
+
case 'Fazer':
|
|
377
|
+
this.lowerFazer(declaracao);
|
|
378
|
+
return;
|
|
379
|
+
case 'Escolha':
|
|
380
|
+
this.lowerEscolha(declaracao);
|
|
381
|
+
return;
|
|
382
|
+
case 'Retorna':
|
|
383
|
+
this.lowerRetorna(declaracao);
|
|
384
|
+
return;
|
|
385
|
+
case 'Importar':
|
|
386
|
+
return;
|
|
387
|
+
case 'Classe':
|
|
388
|
+
throw new Error('Classes não são suportadas pelo tradutor para x64.');
|
|
389
|
+
case 'Tente':
|
|
390
|
+
throw new Error('Tente/pegue não é suportado pelo tradutor para x64.');
|
|
391
|
+
case 'Falhar':
|
|
392
|
+
throw new Error('Falhar não é suportado pelo tradutor para x64.');
|
|
393
|
+
default:
|
|
394
|
+
throw new Error(`Declaração '${nomeClasse}' não suportada pelo tradutor para x64.`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Uma `var`/`const` de topo referenciada por alguma função já foi pré-registrada como
|
|
399
|
+
* global (ver LoweringX64.lowerPrograma passo 1) — aqui só emitimos a inicialização
|
|
400
|
+
* apontando para ela, sem criar um slot local/SSA.
|
|
401
|
+
*/
|
|
402
|
+
lowerVarOuConst(declaracao, ehConst) {
|
|
403
|
+
const nome = declaracao.simbolo.lexema;
|
|
404
|
+
const contexto = `${ehConst ? 'Constante' : 'Variável'} '${nome}'`;
|
|
405
|
+
const ehGlobalPromovida = this.programa.globaisEscalares.has(nome) || this.programa.globaisArranjos.has(nome);
|
|
406
|
+
if (declaracao.inicializador instanceof construtos_1.Vetor) {
|
|
407
|
+
const elementos = declaracao.inicializador.elementos;
|
|
408
|
+
let info;
|
|
409
|
+
if (ehGlobalPromovida) {
|
|
410
|
+
info = this.programa.globaisArranjos.get(nome);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
const tipoElemento = (0, tipos_x64_1.resolverTipoElementoVetor)(declaracao.tipo, contexto);
|
|
414
|
+
info = { id: nome, tamanho: elementos.length, tipoElemento };
|
|
415
|
+
this.declararLocalArray(nome, info);
|
|
416
|
+
}
|
|
417
|
+
elementos.forEach((elemento, indice) => {
|
|
418
|
+
const valor = this.lowerConstruto(elemento);
|
|
419
|
+
this.emitir({ op: 'indiceEscrever', arranjo: nome, indice: (0, ir_1.valorConstante)(indice), valor });
|
|
420
|
+
});
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (!ehGlobalPromovida) {
|
|
424
|
+
const tipo = (0, tipos_x64_1.resolverTipoEscalar)(declaracao.tipo, contexto);
|
|
425
|
+
this.declararLocalEscalar(nome, tipo);
|
|
426
|
+
}
|
|
427
|
+
const valorInicial = declaracao.inicializador ? this.lowerConstruto(declaracao.inicializador) : (0, ir_1.valorConstante)(0);
|
|
428
|
+
this.escreverEscalar(nome, valorInicial);
|
|
429
|
+
}
|
|
430
|
+
lowerEscreva(declaracao) {
|
|
431
|
+
const argumento = declaracao.argumentos[0];
|
|
432
|
+
if (argumento instanceof construtos_1.Literal && argumento.tipo === 'texto') {
|
|
433
|
+
const rotulo = this.literalTexto(String(argumento.valor));
|
|
434
|
+
this.emitir({ op: 'imprimirTexto', rotulo });
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const valor = this.lowerConstruto(argumento);
|
|
438
|
+
this.emitir({ op: 'imprimirNumero', valor });
|
|
439
|
+
}
|
|
440
|
+
lowerCondicao(condicao) {
|
|
441
|
+
return this.lowerConstruto(condicao);
|
|
442
|
+
}
|
|
443
|
+
lowerSe(declaracao) {
|
|
444
|
+
const blocoFim = this.criarBloco();
|
|
445
|
+
const pares = [
|
|
446
|
+
{ condicao: declaracao.condicao, caminho: declaracao.caminhoEntao },
|
|
447
|
+
...(declaracao.caminhosSeSenao ?? []).map((c) => ({ condicao: c.condicao, caminho: c.caminho })),
|
|
448
|
+
];
|
|
449
|
+
const lowerCadeia = (indice) => {
|
|
450
|
+
if (indice >= pares.length) {
|
|
451
|
+
if (declaracao.caminhoSenao)
|
|
452
|
+
this.lowerDeclaracao(declaracao.caminhoSenao);
|
|
453
|
+
this.terminarCom({ op: 'salto', alvo: blocoFim });
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const condicaoValor = this.lowerCondicao(pares[indice].condicao);
|
|
457
|
+
const blocoEntao = this.criarBloco();
|
|
458
|
+
const blocoProximo = this.criarBloco();
|
|
459
|
+
this.terminarCom({ op: 'saltoCondicional', condicao: condicaoValor, verdadeiro: blocoEntao, falso: blocoProximo });
|
|
460
|
+
this.irPara(blocoEntao);
|
|
461
|
+
this.lowerDeclaracao(pares[indice].caminho);
|
|
462
|
+
this.terminarCom({ op: 'salto', alvo: blocoFim });
|
|
463
|
+
this.irPara(blocoProximo);
|
|
464
|
+
lowerCadeia(indice + 1);
|
|
465
|
+
};
|
|
466
|
+
lowerCadeia(0);
|
|
467
|
+
this.irPara(blocoFim);
|
|
468
|
+
}
|
|
469
|
+
lowerEnquanto(declaracao) {
|
|
470
|
+
const blocoCondicao = this.criarBloco();
|
|
471
|
+
const blocoCorpo = this.criarBloco();
|
|
472
|
+
const blocoFim = this.criarBloco();
|
|
473
|
+
this.terminarCom({ op: 'salto', alvo: blocoCondicao });
|
|
474
|
+
this.irPara(blocoCondicao);
|
|
475
|
+
const condicaoValor = this.lowerCondicao(declaracao.condicao);
|
|
476
|
+
this.terminarCom({ op: 'saltoCondicional', condicao: condicaoValor, verdadeiro: blocoCorpo, falso: blocoFim });
|
|
477
|
+
this.irPara(blocoCorpo);
|
|
478
|
+
this.lowerDeclaracao(declaracao.corpo);
|
|
479
|
+
this.terminarCom({ op: 'salto', alvo: blocoCondicao });
|
|
480
|
+
this.irPara(blocoFim);
|
|
481
|
+
}
|
|
482
|
+
lowerPara(declaracao) {
|
|
483
|
+
if (declaracao.inicializador) {
|
|
484
|
+
if (Array.isArray(declaracao.inicializador)) {
|
|
485
|
+
for (const decl of declaracao.inicializador)
|
|
486
|
+
this.lowerDeclaracao(decl);
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
this.lowerDeclaracao(declaracao.inicializador);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const blocoCondicao = this.criarBloco();
|
|
493
|
+
const blocoCorpo = this.criarBloco();
|
|
494
|
+
const blocoIncremento = this.criarBloco();
|
|
495
|
+
const blocoFim = this.criarBloco();
|
|
496
|
+
this.terminarCom({ op: 'salto', alvo: blocoCondicao });
|
|
497
|
+
this.irPara(blocoCondicao);
|
|
498
|
+
const condicaoValor = declaracao.condicao ? this.lowerCondicao(declaracao.condicao) : (0, ir_1.valorConstante)(true);
|
|
499
|
+
this.terminarCom({ op: 'saltoCondicional', condicao: condicaoValor, verdadeiro: blocoCorpo, falso: blocoFim });
|
|
500
|
+
this.irPara(blocoCorpo);
|
|
501
|
+
this.lowerDeclaracao(declaracao.corpo);
|
|
502
|
+
this.terminarCom({ op: 'salto', alvo: blocoIncremento });
|
|
503
|
+
this.irPara(blocoIncremento);
|
|
504
|
+
if (declaracao.incrementar)
|
|
505
|
+
this.lowerConstruto(declaracao.incrementar);
|
|
506
|
+
this.terminarCom({ op: 'salto', alvo: blocoCondicao });
|
|
507
|
+
this.irPara(blocoFim);
|
|
508
|
+
}
|
|
509
|
+
lowerParaCada(declaracao) {
|
|
510
|
+
if (!(declaracao.vetorOuDicionario instanceof construtos_1.Vetor) && !(declaracao.vetorOuDicionario instanceof construtos_1.Variavel)) {
|
|
511
|
+
throw new Error('para-cada só é suportado sobre um vetor literal ou uma variável de vetor de tamanho fixo.');
|
|
512
|
+
}
|
|
513
|
+
if (!(declaracao.variavelIteracao instanceof construtos_1.Variavel)) {
|
|
514
|
+
throw new Error('para-cada requer uma única variável de iteração (dupla/dicionário não suportado).');
|
|
515
|
+
}
|
|
516
|
+
const nomeVetor = declaracao.vetorOuDicionario instanceof construtos_1.Variavel
|
|
517
|
+
? declaracao.vetorOuDicionario.simbolo.lexema
|
|
518
|
+
: undefined;
|
|
519
|
+
if (!nomeVetor) {
|
|
520
|
+
throw new Error('para-cada só é suportado sobre uma variável de vetor já declarada.');
|
|
521
|
+
}
|
|
522
|
+
const info = this.resolverArranjoInfo(nomeVetor);
|
|
523
|
+
const nomeIteracao = declaracao.variavelIteracao.simbolo.lexema;
|
|
524
|
+
this.declararLocalEscalar(nomeIteracao, info.tipoElemento);
|
|
525
|
+
const nomeIndice = `__indice_${nomeIteracao}__`;
|
|
526
|
+
this.declararLocalEscalar(nomeIndice, 'inteiro');
|
|
527
|
+
this.emitir({ op: 'const', dst: nomeIndice, valor: 0 });
|
|
528
|
+
const blocoCondicao = this.criarBloco();
|
|
529
|
+
const blocoCorpo = this.criarBloco();
|
|
530
|
+
const blocoIncremento = this.criarBloco();
|
|
531
|
+
const blocoFim = this.criarBloco();
|
|
532
|
+
this.terminarCom({ op: 'salto', alvo: blocoCondicao });
|
|
533
|
+
this.irPara(blocoCondicao);
|
|
534
|
+
const tempCmp = this.novoTemp();
|
|
535
|
+
this.emitir({
|
|
536
|
+
op: 'bin',
|
|
537
|
+
dst: tempCmp,
|
|
538
|
+
operador: '<',
|
|
539
|
+
esquerda: (0, ir_1.valorRegistrador)(nomeIndice),
|
|
540
|
+
direita: (0, ir_1.valorConstante)(info.tamanho),
|
|
541
|
+
});
|
|
542
|
+
this.terminarCom({
|
|
543
|
+
op: 'saltoCondicional',
|
|
544
|
+
condicao: (0, ir_1.valorRegistrador)(tempCmp),
|
|
545
|
+
verdadeiro: blocoCorpo,
|
|
546
|
+
falso: blocoFim,
|
|
547
|
+
});
|
|
548
|
+
this.irPara(blocoCorpo);
|
|
549
|
+
const tempElemento = this.novoTemp();
|
|
550
|
+
this.emitir({ op: 'indiceLer', dst: tempElemento, arranjo: nomeVetor, indice: (0, ir_1.valorRegistrador)(nomeIndice) });
|
|
551
|
+
this.emitir({ op: 'copia', dst: nomeIteracao, src: (0, ir_1.valorRegistrador)(tempElemento) });
|
|
552
|
+
this.lowerDeclaracao(declaracao.corpo);
|
|
553
|
+
this.terminarCom({ op: 'salto', alvo: blocoIncremento });
|
|
554
|
+
this.irPara(blocoIncremento);
|
|
555
|
+
const tempIndiceNovo = this.novoTemp();
|
|
556
|
+
this.emitir({
|
|
557
|
+
op: 'bin',
|
|
558
|
+
dst: tempIndiceNovo,
|
|
559
|
+
operador: '+',
|
|
560
|
+
esquerda: (0, ir_1.valorRegistrador)(nomeIndice),
|
|
561
|
+
direita: (0, ir_1.valorConstante)(1),
|
|
562
|
+
});
|
|
563
|
+
this.emitir({ op: 'copia', dst: nomeIndice, src: (0, ir_1.valorRegistrador)(tempIndiceNovo) });
|
|
564
|
+
this.terminarCom({ op: 'salto', alvo: blocoCondicao });
|
|
565
|
+
this.irPara(blocoFim);
|
|
566
|
+
}
|
|
567
|
+
lowerFazer(declaracao) {
|
|
568
|
+
const blocoCorpo = this.criarBloco();
|
|
569
|
+
const blocoFim = this.criarBloco();
|
|
570
|
+
this.terminarCom({ op: 'salto', alvo: blocoCorpo });
|
|
571
|
+
this.irPara(blocoCorpo);
|
|
572
|
+
this.lowerDeclaracao(declaracao.caminhoFazer);
|
|
573
|
+
const condicaoValor = this.lowerCondicao(declaracao.condicaoEnquanto);
|
|
574
|
+
this.terminarCom({ op: 'saltoCondicional', condicao: condicaoValor, verdadeiro: blocoCorpo, falso: blocoFim });
|
|
575
|
+
this.irPara(blocoFim);
|
|
576
|
+
}
|
|
577
|
+
lowerEscolha(declaracao) {
|
|
578
|
+
const valorEscolha = this.lowerConstruto(declaracao.identificadorOuLiteral);
|
|
579
|
+
const blocoFim = this.criarBloco();
|
|
580
|
+
const lowerCaminhos = (indice) => {
|
|
581
|
+
if (indice >= declaracao.caminhos.length) {
|
|
582
|
+
if (declaracao.caminhoPadrao) {
|
|
583
|
+
for (const decl of declaracao.caminhoPadrao.declaracoes)
|
|
584
|
+
this.lowerDeclaracao(decl);
|
|
585
|
+
}
|
|
586
|
+
this.terminarCom({ op: 'salto', alvo: blocoFim });
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
const caminho = declaracao.caminhos[indice];
|
|
590
|
+
const condicaoCaso = caminho.condicoes[0];
|
|
591
|
+
const valorCaso = this.lowerConstruto(condicaoCaso);
|
|
592
|
+
const tempCmp = this.novoTemp();
|
|
593
|
+
this.emitir({ op: 'bin', dst: tempCmp, operador: '==', esquerda: valorEscolha, direita: valorCaso });
|
|
594
|
+
const blocoCorpo = this.criarBloco();
|
|
595
|
+
const blocoProximo = this.criarBloco();
|
|
596
|
+
this.terminarCom({
|
|
597
|
+
op: 'saltoCondicional',
|
|
598
|
+
condicao: (0, ir_1.valorRegistrador)(tempCmp),
|
|
599
|
+
verdadeiro: blocoCorpo,
|
|
600
|
+
falso: blocoProximo,
|
|
601
|
+
});
|
|
602
|
+
this.irPara(blocoCorpo);
|
|
603
|
+
for (const decl of caminho.declaracoes)
|
|
604
|
+
this.lowerDeclaracao(decl);
|
|
605
|
+
this.terminarCom({ op: 'salto', alvo: blocoFim });
|
|
606
|
+
this.irPara(blocoProximo);
|
|
607
|
+
lowerCaminhos(indice + 1);
|
|
608
|
+
};
|
|
609
|
+
lowerCaminhos(0);
|
|
610
|
+
this.irPara(blocoFim);
|
|
611
|
+
}
|
|
612
|
+
lowerRetorna(declaracao) {
|
|
613
|
+
if (declaracao.valor) {
|
|
614
|
+
const valor = this.lowerConstruto(declaracao.valor);
|
|
615
|
+
this.terminarCom({ op: 'retorno', valor });
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
this.terminarCom({ op: 'retorno' });
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
// --- Construtos (expressões) ---
|
|
622
|
+
lowerConstruto(construto) {
|
|
623
|
+
const nomeClasse = construto.constructor.name;
|
|
624
|
+
switch (nomeClasse) {
|
|
625
|
+
case 'Literal':
|
|
626
|
+
return this.lowerLiteral(construto);
|
|
627
|
+
case 'Variavel':
|
|
628
|
+
return this.lerEscalar(construto.simbolo.lexema);
|
|
629
|
+
case 'Agrupamento':
|
|
630
|
+
return this.lowerConstruto(construto.expressao);
|
|
631
|
+
case 'Binario':
|
|
632
|
+
return this.lowerBinario(construto);
|
|
633
|
+
case 'Logico':
|
|
634
|
+
return this.lowerLogico(construto);
|
|
635
|
+
case 'Unario':
|
|
636
|
+
return this.lowerUnario(construto);
|
|
637
|
+
case 'Atribuir':
|
|
638
|
+
return this.lowerAtribuir(construto);
|
|
639
|
+
case 'AtribuicaoPorIndice':
|
|
640
|
+
return this.lowerAtribuicaoPorIndice(construto);
|
|
641
|
+
case 'AcessoIndiceVariavel':
|
|
642
|
+
return this.lowerAcessoIndice(construto);
|
|
643
|
+
case 'Chamada':
|
|
644
|
+
return this.lowerChamada(construto);
|
|
645
|
+
case 'Leia':
|
|
646
|
+
throw new Error("'leia' não é suportado pelo tradutor para x64.");
|
|
647
|
+
case 'DefinirValor':
|
|
648
|
+
case 'AcessoMetodo':
|
|
649
|
+
case 'TipoDe':
|
|
650
|
+
throw new Error(`'${nomeClasse}' requer modelo de objetos e não é suportado pelo tradutor para x64.`);
|
|
651
|
+
default:
|
|
652
|
+
throw new Error(`Expressão '${nomeClasse}' não suportada pelo tradutor para x64.`);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
lowerLiteral(construto) {
|
|
656
|
+
if (typeof construto.valor === 'number')
|
|
657
|
+
return (0, ir_1.valorConstante)(construto.valor);
|
|
658
|
+
if (typeof construto.valor === 'boolean')
|
|
659
|
+
return (0, ir_1.valorConstante)(construto.valor ? 1 : 0);
|
|
660
|
+
if (typeof construto.valor === 'bigint')
|
|
661
|
+
return (0, ir_1.valorConstante)(construto.valor);
|
|
662
|
+
if (typeof construto.valor === 'string') {
|
|
663
|
+
const rotulo = this.literalTexto(construto.valor);
|
|
664
|
+
const temp = this.novoTemp();
|
|
665
|
+
this.emitir({ op: 'enderecoRotulo', dst: temp, rotulo });
|
|
666
|
+
return (0, ir_1.valorRegistrador)(temp);
|
|
667
|
+
}
|
|
668
|
+
throw new Error(`Literal do tipo '${construto.tipo}' não suportado pelo tradutor para x64.`);
|
|
669
|
+
}
|
|
670
|
+
lowerBinario(construto) {
|
|
671
|
+
if (construto.esquerda.tipo === 'texto' || construto.direita.tipo === 'texto') {
|
|
672
|
+
throw new Error('Operações aritméticas sobre texto não são suportadas pelo tradutor para x64.');
|
|
673
|
+
}
|
|
674
|
+
const esquerda = this.lowerConstruto(construto.esquerda);
|
|
675
|
+
const direita = this.lowerConstruto(construto.direita);
|
|
676
|
+
const operador = construto.operador.lexema;
|
|
677
|
+
if (!OPERADORES_BINARIOS.has(operador)) {
|
|
678
|
+
throw new Error(`Operador '${operador}' não suportado pelo tradutor para x64.`);
|
|
679
|
+
}
|
|
680
|
+
const dst = this.novoTemp();
|
|
681
|
+
this.emitir({ op: 'bin', dst, operador: operador, esquerda, direita });
|
|
682
|
+
return (0, ir_1.valorRegistrador)(dst);
|
|
683
|
+
}
|
|
684
|
+
lowerLogico(construto) {
|
|
685
|
+
const ehE = construto.operador.lexema === 'e' || construto.operador.lexema === '&&';
|
|
686
|
+
const ehOu = construto.operador.lexema === 'ou' || construto.operador.lexema === '||';
|
|
687
|
+
if (!ehE && !ehOu) {
|
|
688
|
+
throw new Error(`Operador lógico '${construto.operador.lexema}' não suportado pelo tradutor para x64.`);
|
|
689
|
+
}
|
|
690
|
+
const nomeResultado = `%logico${this.novoTemp()}`;
|
|
691
|
+
this.declararLocalEscalar(nomeResultado, 'logico');
|
|
692
|
+
const blocoAvaliaDireita = this.criarBloco();
|
|
693
|
+
const blocoFim = this.criarBloco();
|
|
694
|
+
const esquerda = this.lowerConstruto(construto.esquerda);
|
|
695
|
+
this.emitir({ op: 'copia', dst: nomeResultado, src: esquerda });
|
|
696
|
+
if (ehE) {
|
|
697
|
+
const blocoCurto = this.criarBloco();
|
|
698
|
+
this.terminarCom({
|
|
699
|
+
op: 'saltoCondicional',
|
|
700
|
+
condicao: esquerda,
|
|
701
|
+
verdadeiro: blocoAvaliaDireita,
|
|
702
|
+
falso: blocoCurto,
|
|
703
|
+
});
|
|
704
|
+
this.irPara(blocoCurto);
|
|
705
|
+
this.terminarCom({ op: 'salto', alvo: blocoFim });
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
const blocoCurto = this.criarBloco();
|
|
709
|
+
this.terminarCom({
|
|
710
|
+
op: 'saltoCondicional',
|
|
711
|
+
condicao: esquerda,
|
|
712
|
+
verdadeiro: blocoCurto,
|
|
713
|
+
falso: blocoAvaliaDireita,
|
|
714
|
+
});
|
|
715
|
+
this.irPara(blocoCurto);
|
|
716
|
+
this.terminarCom({ op: 'salto', alvo: blocoFim });
|
|
717
|
+
}
|
|
718
|
+
this.irPara(blocoAvaliaDireita);
|
|
719
|
+
const direita = this.lowerConstruto(construto.direita);
|
|
720
|
+
this.emitir({ op: 'copia', dst: nomeResultado, src: direita });
|
|
721
|
+
this.terminarCom({ op: 'salto', alvo: blocoFim });
|
|
722
|
+
this.irPara(blocoFim);
|
|
723
|
+
let resultado = (0, ir_1.valorRegistrador)(nomeResultado);
|
|
724
|
+
if (construto.negado) {
|
|
725
|
+
const negadoTemp = this.novoTemp();
|
|
726
|
+
this.emitir({ op: 'nao', dst: negadoTemp, src: resultado });
|
|
727
|
+
resultado = (0, ir_1.valorRegistrador)(negadoTemp);
|
|
728
|
+
}
|
|
729
|
+
return resultado;
|
|
730
|
+
}
|
|
731
|
+
lowerUnario(construto) {
|
|
732
|
+
const operador = construto.operador.lexema;
|
|
733
|
+
if (operador === '++' || operador === '--') {
|
|
734
|
+
if (!(construto.operando instanceof construtos_1.Variavel)) {
|
|
735
|
+
throw new Error('++/-- só são suportados sobre uma variável simples.');
|
|
736
|
+
}
|
|
737
|
+
const nome = construto.operando.simbolo.lexema;
|
|
738
|
+
const valorAntigo = this.lerEscalar(nome);
|
|
739
|
+
const novoValor = this.novoTemp();
|
|
740
|
+
this.emitir({
|
|
741
|
+
op: 'bin',
|
|
742
|
+
dst: novoValor,
|
|
743
|
+
operador: operador === '++' ? '+' : '-',
|
|
744
|
+
esquerda: valorAntigo,
|
|
745
|
+
direita: (0, ir_1.valorConstante)(1),
|
|
746
|
+
});
|
|
747
|
+
this.escreverEscalar(nome, (0, ir_1.valorRegistrador)(novoValor));
|
|
748
|
+
return construto.incidenciaOperador === 'DEPOIS' ? valorAntigo : (0, ir_1.valorRegistrador)(novoValor);
|
|
749
|
+
}
|
|
750
|
+
const operando = this.lowerConstruto(construto.operando);
|
|
751
|
+
const dst = this.novoTemp();
|
|
752
|
+
if (operador === '-') {
|
|
753
|
+
this.emitir({ op: 'neg', dst, src: operando });
|
|
754
|
+
}
|
|
755
|
+
else if (operador === '!' || operador === 'nao') {
|
|
756
|
+
this.emitir({ op: 'nao', dst, src: operando });
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
throw new Error(`Operador unário '${operador}' não suportado pelo tradutor para x64.`);
|
|
760
|
+
}
|
|
761
|
+
return (0, ir_1.valorRegistrador)(dst);
|
|
762
|
+
}
|
|
763
|
+
lowerAtribuir(construto) {
|
|
764
|
+
if (construto.indice) {
|
|
765
|
+
throw new Error('Atribuição indexada deve usar AtribuicaoPorIndice.');
|
|
766
|
+
}
|
|
767
|
+
if (!(construto.alvo instanceof construtos_1.Variavel)) {
|
|
768
|
+
throw new Error('Atribuição só é suportada sobre uma variável simples.');
|
|
769
|
+
}
|
|
770
|
+
const nome = construto.alvo.simbolo.lexema;
|
|
771
|
+
let valor = this.lowerConstruto(construto.valor);
|
|
772
|
+
if (construto.simboloOperador) {
|
|
773
|
+
const operadorComposto = construto.simboloOperador.lexema.replace('=', '');
|
|
774
|
+
const atual = this.lerEscalar(nome);
|
|
775
|
+
const dst = this.novoTemp();
|
|
776
|
+
this.emitir({ op: 'bin', dst, operador: operadorComposto, esquerda: atual, direita: valor });
|
|
777
|
+
valor = (0, ir_1.valorRegistrador)(dst);
|
|
778
|
+
}
|
|
779
|
+
this.escreverEscalar(nome, valor);
|
|
780
|
+
return valor;
|
|
781
|
+
}
|
|
782
|
+
lowerAtribuicaoPorIndice(construto) {
|
|
783
|
+
if (!(construto.objeto instanceof construtos_1.Variavel)) {
|
|
784
|
+
throw new Error('Atribuição por índice só é suportada sobre uma variável de vetor.');
|
|
785
|
+
}
|
|
786
|
+
const nomeVetor = construto.objeto.simbolo.lexema;
|
|
787
|
+
this.resolverArranjoInfo(nomeVetor);
|
|
788
|
+
const indice = this.lowerConstruto(construto.indice);
|
|
789
|
+
const valor = this.lowerConstruto(construto.valor);
|
|
790
|
+
this.emitir({ op: 'indiceEscrever', arranjo: nomeVetor, indice, valor });
|
|
791
|
+
return valor;
|
|
792
|
+
}
|
|
793
|
+
lowerAcessoIndice(construto) {
|
|
794
|
+
if (!(construto.entidadeChamada instanceof construtos_1.Variavel)) {
|
|
795
|
+
throw new Error('Acesso por índice só é suportado sobre uma variável de vetor.');
|
|
796
|
+
}
|
|
797
|
+
const nomeVetor = construto.entidadeChamada.simbolo.lexema;
|
|
798
|
+
this.resolverArranjoInfo(nomeVetor);
|
|
799
|
+
const indice = this.lowerConstruto(construto.indice);
|
|
800
|
+
const dst = this.novoTemp();
|
|
801
|
+
this.emitir({ op: 'indiceLer', dst, arranjo: nomeVetor, indice });
|
|
802
|
+
return (0, ir_1.valorRegistrador)(dst);
|
|
803
|
+
}
|
|
804
|
+
lowerChamada(construto) {
|
|
805
|
+
if (!(construto.entidadeChamada instanceof construtos_1.Variavel)) {
|
|
806
|
+
throw new Error('Só são suportadas chamadas diretas a funções declaradas por nome.');
|
|
807
|
+
}
|
|
808
|
+
const nomeFuncao = construto.entidadeChamada.simbolo.lexema;
|
|
809
|
+
const assinatura = this.assinaturaDe(nomeFuncao);
|
|
810
|
+
if (construto.argumentos.length !== assinatura.parametros.length) {
|
|
811
|
+
throw new Error(`Função '${nomeFuncao}' espera ${assinatura.parametros.length} argumento(s), recebeu ${construto.argumentos.length}.`);
|
|
812
|
+
}
|
|
813
|
+
const argumentos = construto.argumentos.map((argumento) => this.lowerConstruto(argumento));
|
|
814
|
+
const dst = assinatura.tipoRetorno === 'vazio' ? null : this.novoTemp();
|
|
815
|
+
this.emitir({ op: 'chamada', dst, rotulo: nomeFuncao, argumentos });
|
|
816
|
+
return dst ? (0, ir_1.valorRegistrador)(dst) : (0, ir_1.valorConstante)(0);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
/** Só variáveis/constantes declaradas diretamente no nível principal do programa podem virar globais. */
|
|
820
|
+
function coletarDeclaracoesDeTopo(declaracoes) {
|
|
821
|
+
const resultado = [];
|
|
822
|
+
for (const declaracao of declaracoes) {
|
|
823
|
+
if (declaracao instanceof declaracoes_1.Var || declaracao instanceof declaracoes_1.Const)
|
|
824
|
+
resultado.push(declaracao);
|
|
825
|
+
}
|
|
826
|
+
return resultado;
|
|
827
|
+
}
|
|
828
|
+
class LoweringX64 {
|
|
829
|
+
lowerPrograma(declaracoes) {
|
|
830
|
+
const programa = {
|
|
831
|
+
funcoes: [],
|
|
832
|
+
globaisEscalares: new Map(),
|
|
833
|
+
globaisArranjos: new Map(),
|
|
834
|
+
literaisTexto: new Map(),
|
|
835
|
+
};
|
|
836
|
+
const declaracoesFuncao = declaracoes.filter((declaracao) => declaracao instanceof declaracoes_1.FuncaoDeclaracao);
|
|
837
|
+
const demais = declaracoes.filter((declaracao) => !(declaracao instanceof declaracoes_1.FuncaoDeclaracao));
|
|
838
|
+
// 1) Variáveis/constantes top-level referenciadas por alguma função viram globais.
|
|
839
|
+
const nomesTopo = coletarDeclaracoesDeTopo(demais);
|
|
840
|
+
const referenciadasPorFuncoes = new Set();
|
|
841
|
+
for (const decl of declaracoesFuncao) {
|
|
842
|
+
const { referenciadas } = coletarReferenciasEDeclaracoes(decl.funcao.corpo);
|
|
843
|
+
const nomesDeParametro = new Set(decl.funcao.parametros.map((p) => p.nome.lexema));
|
|
844
|
+
for (const nome of referenciadas) {
|
|
845
|
+
if (!nomesDeParametro.has(nome))
|
|
846
|
+
referenciadasPorFuncoes.add(nome);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
for (const decl of nomesTopo) {
|
|
850
|
+
const nome = decl.simbolo.lexema;
|
|
851
|
+
if (!referenciadasPorFuncoes.has(nome))
|
|
852
|
+
continue;
|
|
853
|
+
const contexto = `${decl instanceof declaracoes_1.Const ? 'Constante' : 'Variável'} global '${nome}'`;
|
|
854
|
+
if (decl.inicializador instanceof construtos_1.Vetor) {
|
|
855
|
+
const tipoElemento = (0, tipos_x64_1.resolverTipoElementoVetor)(decl.tipo, contexto);
|
|
856
|
+
programa.globaisArranjos.set(nome, {
|
|
857
|
+
id: nome,
|
|
858
|
+
tamanho: decl.inicializador.elementos.length,
|
|
859
|
+
tipoElemento,
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
programa.globaisEscalares.set(nome, (0, tipos_x64_1.resolverTipoEscalar)(decl.tipo, contexto));
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
// 2) Assinaturas de todas as funções antes de traduzir qualquer corpo (permite chamadas para frente).
|
|
867
|
+
const assinaturas = new Map();
|
|
868
|
+
for (const decl of declaracoesFuncao) {
|
|
869
|
+
const nomeFuncao = decl.simbolo.lexema;
|
|
870
|
+
const parametros = decl.funcao.parametros.map((parametro) => (0, tipos_x64_1.resolverTipoEscalar)(parametro.tipoDado, `Parâmetro '${parametro.nome.lexema}' da função '${nomeFuncao}'`));
|
|
871
|
+
const tipoRetornoTexto = decl.funcao.tipoExplicito ? decl.funcao.tipo : inferirTipoRetorno(decl.funcao.corpo);
|
|
872
|
+
const tipoRetorno = tipoRetornoTexto ? (0, tipos_x64_1.resolverTipoEscalar)(tipoRetornoTexto, `Retorno da função '${nomeFuncao}'`) : 'vazio';
|
|
873
|
+
assinaturas.set(nomeFuncao, { parametros, tipoRetorno });
|
|
874
|
+
}
|
|
875
|
+
// 3) Traduz cada função declarada.
|
|
876
|
+
for (const decl of declaracoesFuncao) {
|
|
877
|
+
programa.funcoes.push(this.lowerFuncaoDeclarada(decl, programa, assinaturas));
|
|
878
|
+
}
|
|
879
|
+
// 4) Traduz o programa principal (tudo que não é declaração de função).
|
|
880
|
+
const construtor = new ConstrutorFuncao('principal', true, programa, assinaturas);
|
|
881
|
+
construtor.lowerBloco(demais);
|
|
882
|
+
construtor.finalizar();
|
|
883
|
+
programa.funcoes.push(construtor.funcao);
|
|
884
|
+
return programa;
|
|
885
|
+
}
|
|
886
|
+
lowerFuncaoDeclarada(decl, programa, assinaturas) {
|
|
887
|
+
const nomeFuncao = decl.simbolo.lexema;
|
|
888
|
+
const assinatura = assinaturas.get(nomeFuncao);
|
|
889
|
+
const construtor = new ConstrutorFuncao(nomeFuncao, false, programa, assinaturas);
|
|
890
|
+
construtor.funcao.tipoRetorno = assinatura.tipoRetorno;
|
|
891
|
+
decl.funcao.parametros.forEach((parametro, indice) => {
|
|
892
|
+
const tipo = assinatura.parametros[indice];
|
|
893
|
+
const nome = parametro.nome.lexema;
|
|
894
|
+
construtor.declararLocalEscalar(nome, tipo);
|
|
895
|
+
construtor.funcao.parametros.push({ nome, registrador: nome, tipo });
|
|
896
|
+
construtor.emitir({ op: 'copia', dst: nome, src: (0, ir_1.valorArgumentoFisico)(indice) });
|
|
897
|
+
});
|
|
898
|
+
construtor.lowerBloco(decl.funcao.corpo);
|
|
899
|
+
construtor.finalizar();
|
|
900
|
+
return construtor.funcao;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
exports.LoweringX64 = LoweringX64;
|
|
904
|
+
//# sourceMappingURL=lowering.js.map
|