-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlinked-list.asm
More file actions
549 lines (398 loc) · 12.5 KB
/
Copy pathlinked-list.asm
File metadata and controls
549 lines (398 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
.macro newNumber_util($number)
add $t0, $zero, $number
addi $a0, $zero, 4
#guardamos:
sw $t0, 0($sp)
subi $sp, $sp, 4
jal malloc #malloc(4)
#recuperamos:
addi $sp, $sp, 4
lw $t0, 0($sp)
sw $t0, 0($v0)
.end_macro
.macro create_util()
### DESCRIPCION ###
# Instancia una lista y devuelve la posicion de memoria donde está la cabeza de esa lista
### Estructura de la lista ###
#|4bytes: inicio | 4bytes: fin | 4bytes: numero de elementos |
### ATRIBUTOS ###
# inicio: dirección donde se encuentra el primer nodo de la lista.
# fin: dirección donde se encuentra el último nodo de la lista. Cuando fin == inicio == 0x0
# es porque no existen nodos en la lista.
# numero de elementos: Cantidad de elementos actualmente insertados en la lista.
### RETURN ###
# La dirección donde se alojó la lista
### Implementacion ###
# Se alojan 12 bytes de espacio; 4 para el valor del atributo "inicio", 4 para el valor del atributo "fin"
# y 4 para el número de elementos. "Inicio" y "fin" empiezan valiendo 0x0 originalmente, y el número
# de elementos empieza en 0.
### --- ###
#Primero tenemos que alojar el espacio total que vamos a necesitar para la lista:
addi $a0, $zero, 12
jal malloc #malloc(12)
#Ahora tenemos que alojar las diferentes parte de la estructura de lista.
#Damos valor al número de elementos:
sw $zero, 8($v0)
#Asignamos 0 a los valores de la head y la tail
sw $zero, ($v0)
sw $zero, 4($v0)
.end_macro
.macro insert_util($lista_ptr,$dir)
### DESCRIPCION ###
# Dada una lista, inserta el elemento cuya direccion es "dir" en la lista
### ENTRADA ###
#lista_ptr: apuntador a la lista (realmente la head de la lista)
#dir: dirección del elemento a añadir en la lista
### ESTRUCTURA DE UN NODO ###
# |4bytes: direccion elemento | 4bytes: siguiente|
### ATRIBUTOS DE UN NODO ###
# direccion elemento: direccion en la memoria donde se encuentra el elemento
# correspondiente con este nodo.
# siguiente: dirección del siguiente nodo en la lista. Si el valor de siguiente es 0x0,
# entonces no tiene siguiente y por lo tanto este nodo es la tail (final) de la lista.
### IMPLEMENTACIÓN ###
# Se instancia el nodo en cuestion utilizando un malloc(8) y luego asignando el contenido
# de sus bytes como se indica en la estructura. Este nodo se asigna como siguiente del nodo "final".
# Si es el primero en ser añadido entonces también se define como head,y en este caso tampoco hay tail
# asi que se asigna directamente sin ser el siguiente de ningún otro nodo.
### --- ###
# Guardamos nuestros datos:
add $t0, $zero, $lista_ptr # t0: apuntador a la lista
add $t1, $zero, $dir # t1: direccion del elemento a añadir
lw $t3, 8($t0) # t3: numero de elementos en la lista
#Ya que usamos malloc, tenemos que guardar los t:
sw $t0, 0($sp)
subi $sp, $sp, 4
sw $t1, 0($sp)
subi $sp, $sp, 4
sw $t3, 0($sp)
subi $sp, $sp, 4
#Creamos el espacio del nodo:
addi $a0, $zero, 8
jal malloc #malloc(8)
#restauramos los t:
addi $sp, $sp, 4
lw $t3, 0($sp)
addi $sp, $sp, 4
lw $t1, 0($sp)
addi $sp, $sp, 4
lw $t0, 0($sp)
#Ahora configuramos las posiciones correspondientes en las posiciones correspondientes
sw $t1, 0($v0)
#Configuramos el siguiente como null
sw $zero, 4($v0)
#¿numero de elementos == 0? No hay tail cuyo siguiente deba ser configurado:
beqz $t3, _correctTail
#Configuramos este elemento como el siguiente de la tail
lw $t2, 4($t0) #t2: apuntador a la tail actual
sw $v0, 4($t2) #Esto hace que el siguiente de la tail de la lista sea igual al nodo que acabamos de crear
_correctTail:
#Configuramos este elemento como tail:
sw $v0, 4($t0)
#Si el contador de elementos es == 0, configuramos este nuevo nodo como primero:
lw $t2, 8($t0) # t2: cantidad de elementos en la lista
bnez $t2, _endInsertSucc # ¿NumeroElementos!=0? No hace falta configurarlo como 0
sw $v0, 0($t0) # head <- nuevo elemento
_endInsertSucc:
li $v0 1
addi $t2, $t2, 1
sw $t2, 8($t0)
.end_macro
.macro delete_util($lista, $pos)
### ENTRADA ###
# lista: apuntador a la lista cuyo elemento queremos eliminar.
# pos: la posicion del elemento en la lista (primero, segundo, tercero...)
### SALIDA ###
# La direccion del elemento que fue eliminado de
### IMPELEMENTACION ###
# Se implementa la eliminacion usual de las listas enlazadas.
# Se consideran varios casos bordes: en el caso donde se pide una
# posicion que excede el tamaño de la lista, el programa genera un error.
# En el caso donde se elimina el único elemento de la lista, esta se vacía.
# en el caso donde se elimina el primero o el último de la lista, estos
# atributos son actualizados en la head de la lista.
### --- ###
#Cargamos en t0 la direccion de la lista:
add $t0, $zero, $lista #t0: direccion de la lista
#cargamos en t1 la posicion del elemento:
add $t1, $zero, $pos #t1: posicion EN la lista
#Cargamos en t2 el numero de elementos de la lista:
lw $t2, 8($t0) #t2: numero de elementos:
#Verificamos si hay algo que eliminar:
# ¿pos > nelements? No hay nada que eliminar, error:
bgt $t1, $t2, _perrorDelete
ble $t1, $t2, _endperrorDelete
_perrorDelete:
li $a0 -4
jal perror
j _endDelete
_endperrorDelete:
#Como podemos eliminar, cargamos en t3 el primer elemento de la lista y vamos buscando:
add $a0, $zero, $t0
jal first
add $t3, $zero, $v0 #t3: apuntador al primer elemento
# Ahora verificamos si el elemento a eliminar es el unico elemento de la lista:
addi $t8, $zero, 1
# ¿numero de elementos NO es igual a 1? saltamos el if.
bne $t2,$t8, _endIfNumElemnEqOne
_ifNumElemnEqOne:
sw $zero, 0($t0) #Quitamos el inicio
sw $zero, 4($t0) #Quitamos el fin
sw $zero, 8($t0) #el número de elementos ahora es 0
lw $v1, 0($t3) #Retornamos la posicion del elemento direccionado
#free($t3) #Liberamos el espacio ocupado por el nodo.
addi $a0, $t3, 0
jal free
addi $v0, $v1, 0
j _endDelete #Terminamos
_endIfNumElemnEqOne:
#Ahora usamos t4 como contador:
addi $t4, $zero, 1 #t4: contador
#iteramos para encontrar el elemento correcto hasta su posicion anterior
subi $t1, $t1, 1
_whileT4NotPrev:
bge $t4, $t1, _endWhileT4NotPrev
add $a0, $zero, $t3
jal next #next(t3)
addi $t3, $v0, 0 #t3 = t3.siguiente
addi $t4, $t4, 1 #t4 += 1
blt $t4, $t1, _whileT4NotPrev
_endWhileT4NotPrev:
addi $t1, $t1, 1
#Encontramos el previo del elemento, ahora guardamos su siguiente.
add $a0, $zero, $t3
jal next
add $t5, $v0, $zero # t5: elemento a eliminar (t3.next)
# Vemos si tenemos que cambiar la head:
addi $t8, $zero, 1
bne $t1, $t8, _endIfPosEqOne # ¿pos != 1? salta el if
_IfPosEqOne:
sw $t5, 0($t0)
#Falta saltar a la parte donde hacemos return
#Retornamos la posicion direccionada por t3:
lw $v1, 0($t3)
#guardamos t0:
sw $t0, 0($sp)
subi $sp, $sp, 4
#free($t3): liberamos el espacio ocupado
addi $a0, $t3, 0
jal free
#Recuperamos el t0
addi $sp, $sp, 4
lw $t0, 0($sp)
addi $v0, $v1, 0
#Actualizamos la cantidad de elementos en la lista:
lw $t1, 8($t0)
subi $t1, $t1, 1
sw $t1, 8($t0)
j _endDelete
_endIfPosEqOne:
#Vemos si tenemos que cambiar el "fin" de la lista:
bne $t1, $t2, _ifPosEqLast # ¿pos != 1? salta el if
_ifPosEqLast:
sw $t3, 4($t0)
_endIfPosEqLast:
#Buscamos el siguiente del elemento a eliminar
add $a0, $zero, $t5
jal next
add $t6, $zero, $v0 # t6 = elementoAEliminar.next
#Configuramos el siguiente del previo correctamente:
sw $t6, 4($t3) #elemento.prev.next = elemento.next
#Cargamos en v1 la dirección del elemento que era direccionado por el nodo eliminado
lw $v1, 0($t5)
#guardamos t0
sw $t0, 0($sp)
subi $sp, $sp, 4
#liberamos el espacio del nodo:
add $a0, $zero, $t5
jal free
#recuperamos t0
addi $sp, $sp, 4
lw $t0, 0($sp)
#Actualizamos la cantidad de elementos en la lista:
lw $t1, 8($t0)
subi $t1, $t1, 1
sw $t1, 8($t0)
add $v0, $zero, $v1
_endDelete:
.end_macro
.macro fun_print_util($nodeDir)
### DESCRIPCION ###
# Utilidad auxiliar para imprimir enteros en una lista enlazada.
### ENTRADA ###
# nodeDir: direccion del nodo que queremos imprimir
### IMPLEMENTACION ###
# Se carga la direccion almacenada en el nodo, y luego el contenido en esa direccion en a0 y
# se imprime.
### --- ###
#Guardamos los registros que vamos a utilizar: a0, v0
sw $v0, 0($sp)
sw $a0, -4($sp)
addi $sp, $sp, -8
# nodedir: es la dirección del nodo que vamos a imprimir
add $t8, $zero, $nodeDir # t8: nodeDir
lw $a0, 0($t8) # a0 <- apuntador al elemento
lw $a0, 0($a0)
addi $v0, $zero, 1
syscall
#Recuperamos lo que guardamos:
lw $a0, 4($sp)
lw $v0, 8($sp)
addi $sp, $sp, 8
.end_macro
.macro print_util($lista,$function)
### ENTRADA ###
# lista: La direccion de la cabeza de la lista cuyo contenido queremos imprimir
# function: funcion utilizada para imprimir un nodo. Necesitamos diferentes
# funciones dependiendo del tipo de la lista porque el tipo de dato que almacena esta lista
# cambia el método de representación.
### Implementacion ###
# Se guarda una variable con la direccion del siguiente elemento a imprimir, y mientras esta direccion
# sea distinta de 0x0, se llama a la funcion de impresion "function" sobre esa direccion, luego se imprime
# un espacio.
### --- ###4
#Guardamos la dirección de lista en t0
add $t0, $zero, $lista
#En t1 vamos a llevar el siguiente elemento a imprimir, empezamos con el primero:
add $a0, $zero, $t0
jal first
add $t1, $zero, $v0 #t1: primer elemento
_printWhileT1NotZero:
beqz $t1, _endPrint
addi $a0, $t1, 0
jalr $function # $function($t1)
#Incrementamos t1:
add $a0, $zero, $t1
jal next
add $t1, $zero, $v0
la $a0, space
addi $v0, $zero, 4
syscall
bnez $t1, _printWhileT1NotZero
#Imprimimos un salto de linea
la $a0, endln
addi $v0, $zero, 4
syscall
_endPrint:
#return: dirección del nodo siguiente al nodo dado.
.end_macro
create:
#ESTA FUNCION NO RECIBE ARGUMENTOS
#Guardamos:
sw $ra, 0($sp)
subi $sp, $sp, 4
sw $a0, 0($sp)
subi $sp, $sp, 4
create_util() #llamamos:
#restauramos:
addi $sp, $sp, 4
lw $a0, 0($sp)
addi $sp, $sp, 4
lw $ra, 0($sp)
jr $ra #volvemos
insert:
# a0: direccion de la lista donde queremos añadir
# a1: direccion del valor que queremos añadir a la lista
#guardamos:
sw $ra, 0($sp)
subi $sp, $sp, 4
insert_util($a0,$a1)
#restauramos:
addi $sp, $sp, 4
lw $ra, 0($sp)
#volvemos
jr $ra
print:
#a0: direccion de la lista que vamos a imprimir
#a1: label de la funcion que usamos para imprimir
sw $ra, 0($sp)
subi $sp, $sp, 4
sw $a0, 0($sp)
subi $sp, $sp, 4
print_util($a0,$a1)
#restauramos:
addi $sp, $sp, 4
lw $a0, 0($sp)
addi $sp, $sp, 4
lw $ra, 0($sp)
#volvemos
jr $ra
fun_print:
# a0: direccion del elemento a imprimir
sw $ra, 0($sp)
subi $sp, $sp, 4
sw $a0, 0($sp)
subi $sp, $sp, 4
sw $a1, 0($sp)
subi $sp, $sp, 4
fun_print_util($a0)
#restauramos:
addi $sp, $sp, 4
sw $a1, 0($sp)
addi $sp, $sp, 4
sw $a0, 0($sp)
addi $sp, $sp, 4
lw $ra, 0($sp)
#volvemos
jr $ra
delete:
# a0: direccion de la listas donde queremos eliminar
# a1: la posicion del elemento que queremos eliminar
#guardamos
sw $ra, 0($sp)
subi $sp, $sp, 4
sw $a0, 0($sp)
subi $sp, $sp, 4
sw $v1, 0($sp)
subi $sp, $sp, 4
delete_util($a0, $a1)
#restauramos:
addi $sp, $sp, 4
lw $v1, 0($sp)
addi $sp, $sp, 4
lw $a0, 0($sp)
addi $sp, $sp, 4
lw $ra, 0($sp)
#volvemos
jr $ra
newNumber:
# a0: número que queremos instanciar
sw $ra, 0($sp)
subi $sp, $sp, 4
newNumber_util($a0)
#restauramos:
addi $sp, $sp, 4
lw $ra, 0($sp)
#volvemos
jr $ra
first:
### DESCRIPCION ###
# dada la direccion de una lista, imprime el "inicio" de esa lista. (La direccion del primer nodo)
### ENTRADA ###
#a0: direccion de la lista cuyo primero queremos obtener
### SALIDA ###
# en v0 se retorna la direccion del primer elemento
### IMPLEMENTACION ###
# Se carga en v0 la palabra ubicada en la direccion contenida por a0
###---###
lw $v0, 0($a0)
jr $ra
#return: la dirección del primer elemento
next:
### DESCRIPCION ###
# dada la direccion de una lista, imprime el "fin" de esa lista. (La direccion del ultimo nodo)
### ENTRADA ###
#a0: direccion de la lista cuyo final queremos obtener
### SALIDA ###
# en v0 se retorna la direccion del ultimo elemento
### IMPLEMENTACION ###
# Se carga en v0 la palabra ubicada en la direccion (a0) + 4
###---###
#Guardamos los registros:
lw $v0, 4($a0)
#volvemos
jr $ra
end:
li $v0 10
syscall
.include "memory-manager.asm"