Oppure

Loading
06/03/13 15:54
dennis87
Ciao a tutti,
devo fare un esercizio che mi chiede

a) Inserimenti di interi in lista. Se la lista è vuota si crea dinamicamente una lista puntata degli interi inseriti dall’utente (0 per terminare l’inserimento). Se la lista non è vuota i nuovi elementi inseriti dall’utente vengono inseriti a partire dalla coda della lista già esistente. In seguito si visualizzano su console gli elementi della lista risultante (dopo l’inserimento) separati da spazi e si ritorna al menù (visualizzare su console la stringa “Nil” nel caso di lista vuota).
b) Eliminazione di interi pari. Si eliminano dalla lista tutti gli elementi con valore intero pari. In
seguito si visualizzano su console gli elementi della lista risultante (dopo l’eliminazione) separati
da spazi e si ritorna al menù (visualizzare su console la stringa “Nil” nel caso di lista vuota).

Ora per il primo punto penso di essere arrivato a conclusione, il secondo ho fatto l'eliminazione al caso se il numero si trova in testa, e si elimina senza problemi, e se il numero si trova in coda, e si elimina senza problemi.
Quando però il numero da eliminare è in coda, esso si elimina, ma se inserisco altri elementi, questi non vengono stampati.
Alltra domanda quale è il metodo per eliminare i numeri che si trovano nel mezzo, cioè non in testa o in coda?
Cioè so che basta modificare il puntatore, ma non capisco come scriverlo.
Questo è il codice che ho scritto fino ad adesso.
# Title: Esercizio 6			
# Author: Dennis Aleandro Boanini			
# Description: Esercizio di progetto n°6
################# Data segment menù ###########
.data
menu1:	.asciiz "\n\n1 - Inserimenti di interi in lista. 0 per terminare l'inserimento.\n\n"
menu2:	.asciiz "2 - Eliminazione di interi dispari.\n\n"    
################# Data segment generale ###########
	end:	.asciiz "\nFine del programma!\n"
	nil:	.asciiz "\nNil\n\n"
	space:	.asciiz " "
	insert:	.asciiz "\nInserisci elemento -> "
	elinsert:	.asciiz "\nElementi inseriti -> "
	inserimento:	.asciiz "\nEffettua una scelta -> "
	test:	.asciiz " -- Di test -- "
	error:	.asciiz "\nScelta sbagliata, rieffettua la scelta per favore "
	creator:	.asciiz " \n\n Created by Dennis Aleandro Boanini "
	coda:	.asciiz "\n coda"
	.align 4
	jump_table: .space 8 # jump table array a 4 word che verra' instanziata dal main con gli indirizzi delle label che chiameranno le corrispondenti procedure
	
################# Code segment #####################
	
.text   
.globl main     

main:
la $s1, jump_table #assegnazione ad $s1 dell'indirizzo base della jump_table
la $t0, juno #assegnazione a $t0 l'indirizzo della case action juno	   	  
sw $t0, 0($s1)   
la $t0, jdue #assegnazione a $t0 l'indirizzo della case action juno   	  
sw $t0, 4($s1) #scrittura nella locazione di memoria di indirizzo $s1+4 del valore contenuto in $t0 	  
  
move $t8 $zero	    		# s0 (= Testa) = 0
move $t9 $zero	    		# s1 (= Coda ) = 0
li $s2, 2	#per controllo se numero pari o dispari
	  
menu:
#Stampa del menu di selezione
 la $a0, menu1 #carico l'indirizzo della stringa menu1 in $a0  	
li $v0, 4 #assegno il codice 4 (print string) a $v0  	
syscall #stampo la stringa menu1
la $a0, menu2
li $v0, 4 
syscall	
	
choice:
# scelta della procedura o dell'uscita
	  li $v0, 4  # $v0 =codice della print_string 
      la $a0, inserimento # $a0 =  indirizzo della stringa 
	  syscall # stampa la stringa prompt	 
	  
# legge la scelta
      li $v0, 5
	  syscall
	  move $s0, $v0   # $s0=scelta 1, 2, 3 o 4
	  
	  sle  $t0, $s0, $zero	# $t0=1 se $s0 <= 0
	  bne  $t0, $zero, choice_err # errore se scelta <=0
	  li   $t0,4
	  sle  $t0, $s0, $t0
	  beq  $t0, $zero, choice_err # errore se scelta >4
 
branch_case:
	  la $s1, jump_table
	  addi $s0, $s0, -1 # tolgo 1 da scelta perche' prima azione nella jump table (in posizione 0) corrisponde alla prima scelta del case
	  add $t0, $s0, $s0 
	  add $t0, $t0, $t0 # ho calcolato (scelta-1) * 4
	  add $t0, $t0, $s1 # sommo all'indirizzo della prima case action l'offset calcolato sopra
	  lw $t0, 0($t0)    # $t0 = indirizzo a cui devo saltare

	  jr $t0 # salto all'indirizzo calcolato

choice_err: 
      li $v0, 4  
      la $a0, error 
      syscall # stampa la stringa errore		
	  				  		  		  	  
      j choice # ritorna alla richiesta di inserimento di un numero tra 1 e 4
	
# prima case action
juno:
	#move $t8 $zero	    		# s0 (= Testa) = 0
	#move $t9 $zero	    		# s1 (= Coda ) = 0
	bne $t8, $zero, inputloop
	li $v0, 4
	la $a0, nil
	syscall
inputloop:                    # inizio loop di input; 
	li $v0, 4
	la $a0, insert
	syscall                       # stampa messaggio

	li $v0, 5
	syscall                       # legge un intero
	beq $v0, $zero, print           # se l'intero letto e' zero, salta all'etichetta print (stampa)
	move $t1 $v0                  # altrimenti t1=input

# inizio inserzione nuovo elemento
	li $v0, 9
	li $a0, 8			#8 byte, 1 per l'intero e uno per il puntatore.
	syscall                      	# chiamata sbrk: restituisce un blocco di 8 byte, puntato da v0: il nuovo record
						# vegono riempiti i due campi del nuovo record:
	sw $t1, 0($v0)              	# campo intero = t1
	sw $zero, 4($v0)              	# campo elemento-successivo = nil
	bne $t8, $zero, link_last       	# se s0!=nil (coda non vuota) vai a link_last
	move $t8, $v0                 	# altrimenti (prima inserzione)  Testa=Coda=v0
	move $t9, $v0

	j inputloop                  	# torna all'inizio del loop di input


link_last:                    # se la coda e' non vuota, collega l'ultimo elemento della lista,
					# puntato da Coda (s1) al nuovo record; dopodiche' modifica Coda 
					# per farlo puntare al nuovo record
	sw $v0, 4($t9)                	# il campo elemento successivo dell'ultimo del record prende v0
	move $t9, $v0                 	# Coda = v0
	j inputloop

print:                       	# loop di stampa di tutti gli elementi della coda, separati da spazi
	move $t0, $t8		# t0 = Testa. t0 verra' usato come puntatore per scorrere gli elementi della lista
	
	li $v0, 4
	la $a0, elinsert
	syscall
	
loop_print:
	beq $t0, $zero, menu		# se  t0 == 0 si e' raggiunta la fine della lista e si esce
	li $v0, 1				# altrimenti si stampa l'elemento corrente. Cioe':
	lw $a0, 0($t0)			# a0 = valore del campo intero dell'elemento corrente (puntato da t0)
	syscall				# stampa valore intero dell'elemento corrente
	li $v0, 4
	la $a0, space			
	syscall				# stampa spazio
	lw $t0, 4($t0)			# t0 = valore del campo elemento-successivo dell'elemento corrente (puntato da t0)
	j loop_print			# salta all'inizio del ciclo di stampa	
	
	j menu
jdue:
	beq $t8, $zero, empty
	move $t0, $t8
trova:
	lw $s0, 0($t0)
	div $s0, $s2
	mfhi $s1
	beq $s1, $zero, checkTC
	lw $t0, 4($t0)
	j trova
checkTC:
	beq $t0, $t8, eliminaT
	beq $t0, $t9, eliminaC
eliminaT:
	lw $t8, 4($t0)
	lw $t0, 4($t0)
	j trova
eliminaC:
	sw $zero, -4($t9)
	lw $t0, 4($t0)
	beq $t0, $zero, print
	j trova
	
empty:
	li $v0, 4
	la $a0, nil
	syscall
	j menu

EDIT del codice: adesso sembra funzionare, per l'eliminazione di elementi in testa in coda, non se è proprio la soluzione ottimale, ma almeno va. Aspetto consigli su una soluzione meglio...
Codice Editato:
# Title: Esercizio 6			
# Author: Dennis Aleandro Boanini			
# Description: Esercizio di progetto n°6
################# Data segment menù ###########
.data
menu1:	.asciiz "\n\n1 - Inserimenti di interi in lista. 0 per terminare l'inserimento.\n\n"
menu2:	.asciiz "2 - Eliminazione di interi dispari.\n\n"    
################# Data segment generale ###########
end:	.asciiz "\nFine del programma!\n"
nil:	.asciiz "\nNil\n\n"
space:	.asciiz " "
insert:	.asciiz "\nInserisci elemento -> "
elinsert:	.asciiz "\nElementi inseriti -> "
inserimento:	.asciiz "\nEffettua una scelta -> "
test:	.asciiz " -- Di test -- "
error:	.asciiz "\nScelta sbagliata, rieffettua la scelta per favore "
creator:	.asciiz " \n\n Created by Dennis Aleandro Boanini "
mezzo:	.asciiz "\n mezzo"
.align 4
jump_table: .space 8 # jump table array a 4 word che verra' instanziata dal main con gli indirizzi delle label che chiameranno le corrispondenti procedure
	
################# Code segment #####################
.text   
.globl main     

main:
la $s1, jump_table #assegnazione ad $s1 dell'indirizzo base della jump_table
la $t0, juno #assegnazione a $t0 l'indirizzo della case action juno	   	  
sw $t0, 0($s1)   
la $t0, jdue #assegnazione a $t0 l'indirizzo della case action juno   	  
sw $t0, 4($s1) #scrittura nella locazione di memoria di indirizzo $s1+4 del valore contenuto in $t0 	  
  
move $t8 $zero	    		# s0 (= Testa) = 0
move $t9 $zero	    		# s1 (= Coda ) = 0
li $s2, 2	#per controllo se numero pari o dispari
	  
menu:
#Stampa del menu di selezione
 la $a0, menu1 #carico l'indirizzo della stringa menu1 in $a0  	
li $v0, 4 #assegno il codice 4 (print string) a $v0  	
syscall #stampo la stringa menu1
la $a0, menu2
li $v0, 4 
syscall	
	
choice:
# scelta della procedura o dell'uscita
	  li $v0, 4  # $v0 =codice della print_string 
      la $a0, inserimento # $a0 =  indirizzo della stringa 
	  syscall # stampa la stringa prompt	 
	  
# legge la scelta
      li $v0, 5
	  syscall
	  move $s0, $v0   # $s0=scelta 1, 2, 3 o 4
	  
	  sle  $t0, $s0, $zero	# $t0=1 se $s0 <= 0
	  bne  $t0, $zero, choice_err # errore se scelta <=0
	  li   $t0,4
	  sle  $t0, $s0, $t0
	  beq  $t0, $zero, choice_err # errore se scelta >4
 
branch_case:
	  la $s1, jump_table
	  addi $s0, $s0, -1 # tolgo 1 da scelta perche' prima azione nella jump table (in posizione 0) corrisponde alla prima scelta del case
	  add $t0, $s0, $s0 
	  add $t0, $t0, $t0 # ho calcolato (scelta-1) * 4
	  add $t0, $t0, $s1 # sommo all'indirizzo della prima case action l'offset calcolato sopra
	  lw $t0, 0($t0)    # $t0 = indirizzo a cui devo saltare

	  jr $t0 # salto all'indirizzo calcolato

choice_err: 
      li $v0, 4  
      la $a0, error 
      syscall # stampa la stringa errore		
	  				  		  		  	  
      j choice # ritorna alla richiesta di inserimento di un numero tra 1 e 4
	
# prima case action
juno:
	#move $t8 $zero	    		# s0 (= Testa) = 0
	#move $t9 $zero	    		# s1 (= Coda ) = 0
	bne $t8, $zero, inputloop
	li $v0, 4
	la $a0, nil
	syscall
inputloop:                    # inizio loop di input; 
	li $v0, 4
	la $a0, insert
	syscall                       # stampa messaggio

	li $v0, 5
	syscall                       # legge un intero
	beq $v0, $zero, print           # se l'intero letto e' zero, salta all'etichetta print (stampa)
	move $t1 $v0                  # altrimenti t1=input

# inizio inserzione nuovo elemento
	li $v0, 9
	li $a0, 8			#8 byte, 1 per l'intero e uno per il puntatore.
	syscall                      	# chiamata sbrk: restituisce un blocco di 8 byte, puntato da v0: il nuovo record
						# vegono riempiti i due campi del nuovo record:
	sw $t1, 0($v0)              	# campo intero = t1
	sw $zero, 4($v0)              	# campo elemento-successivo = nil
	bne $t8, $zero, link_last       	# se s0!=nil (coda non vuota) vai a link_last
	move $t8, $v0                 	# altrimenti (prima inserzione)  Testa=Coda=v0
	move $t9, $v0

	j inputloop                  	# torna all'inizio del loop di input


link_last:                    # se la coda e' non vuota, collega l'ultimo elemento della lista,
					# puntato da Coda (s1) al nuovo record; dopodiche' modifica Coda 
					# per farlo puntare al nuovo record
	sw $v0, 4($t9)                	# il campo elemento successivo dell'ultimo del record prende v0
	move $t9, $v0                 	# Coda = v0
	j inputloop

print:                       	# loop di stampa di tutti gli elementi della coda, separati da spazi
	move $t0, $t8		# t0 = Testa. t0 verra' usato come puntatore per scorrere gli elementi della lista
	
	li $v0, 4
	la $a0, elinsert
	syscall
	
loop_print:
	beq $t0, $zero, menu		# se  t0 == 0 si e' raggiunta la fine della lista e si esce
	li $v0, 1				# altrimenti si stampa l'elemento corrente. Cioe':
	lw $a0, 0($t0)			# a0 = valore del campo intero dell'elemento corrente (puntato da t0)
	syscall				# stampa valore intero dell'elemento corrente
	li $v0, 4
	la $a0, space			
	syscall				# stampa spazio
	lw $t0, 4($t0)			# t0 = valore del campo elemento-successivo dell'elemento corrente (puntato da t0)
	j loop_print			# salta all'inizio del ciclo di stampa	
	
	j menu
jdue:
	beq $t8, $zero, empty
	move $t0, $t8
trova:
	lw $s0, 0($t0)
	div $s0, $s2
	mfhi $s1
	beq $s1, $zero, checkTC
	lw $t0, 4($t0)
	beq $t0, $zero, print
	j trova
checkTC:
	beq $t0, $t8, eliminaT
	beq $t0, $t9, eliminaC
	j eliminaM
eliminaT:
	lw $t8, 4($t0)
	lw $t0, 4($t0)
	j trova
eliminaC:
	sw $zero, -4($t0)
	#lw $t9, -4($t0)
	addi $t9, $t9, -8
	#move $s5, $t0
	lw $t0, 4($t0)
	beq $t0, $zero, print
	j trova
eliminaM:
	lw $t0, 4($t0)
	sw $t0, -12($t0)
	j trova
empty:
	li $v0, 4
	la $a0, nil
	syscall
	j menu

Ultima modifica effettuata da dennis87 07/03/13 16:53
aaa
06/03/13 17:08
pierotofy
Intanto correggi qui:

menu2:  .asciiz "2 - Eliminazione di interi dispari.\n\n"   


Con:

menu2:  .asciiz "2 - Eliminazione di interi pari.\n\n"


Con un test input 1,2,3,4

checkTC:
        beq $t0, $t8, eliminaT
        beq $t0, $t9, eliminaC
eliminaT:
        lw $t8, 4($t0)
        lw $t0, 4($t0)
        j trova


Al momento di eliminare 2 il programma dovrebbe branciare su eliminaC, ma non lo fa. I valori di $t0 e $t9 sono:

$t0    0x10040008
$t9    0x10040018

Il codice esegue la parte eliminaT per un elemento che non e' la testa, quindi non funziona.

Ti consiglio di scaricare questo courses.missouristate.edu/KenVollmar/MARS/… e di fare un po' di debugging (tenendo d'occhio le registers, il segmento heap e passo per passo guardare cosa fa il programma).
Il mio blog: piero.dev
07/03/13 8:08
dennis87
Grazie pierotofy per la risposta.
Per quanto riguarda il menù era soltanto un copia e incolla per fare un test, per quanto riguarda il codice, al momento attuale, funziona solamente se do in input
4 7 7
7 7 4
7 7
4 7 7 4
ovvero riesce ad eliminare solo gli elementi in testa, in coda e contemporaneamente in testa e in coda e in tutti e 4 i casi restituisce sempre i valori 7 7. Se faccio l'esempio tuo 1 2 3 4 il codice darà errore perche il 2 non è ne in testa ne in coda e quindi il programma va in crash.
Adesso mi iniziano le lezioni, dopo provo a dare un occhiata al tuo link e in caso di altri problemi magari riposto qui.
Grazie ancora per la risposta.
aaa
07/03/13 14:58
dennis87
MARS programma molto meglio di QtSpim e debugging ottimo, ma ancora non ho capito come fare per eliminare un elemento che non è la testa o la coda, ma elemento di mezzo.
Quando arrivo all'elemento da cancellare, come modifico il puntatore dell'elemento precedente per farlo puntare all'elemento successivo a quello da cancellare?

EDIT:
Ho editato il secondo codice del primo post.
Adesso sembra quasi funzionare.
Ho provato a dare in input queste seguenze di numeri: 4777, 7774, 4774, 7477, 4747, 7474, 47474, 4477, 7744, 74472, 7447, 123456789, funziona su tutti tranne che su 7744 che stampa 774, 74472 e 7447 che stampano 747.
Continuo a lavorarci.
Ultima modifica effettuata da dennis87 07/03/13 16:57
aaa
09/03/13 13:18
Devi scorrere la lista, elemento per elemento, se l' elemento successivo è pari lo elimini e modifichi il puntatore
09/03/13 15:07
dennis87
Si lo so ma il problema mi si presenta quando ho piu interi da eliminare consecutivamente, come nel caso 7 4 4 7...che mi rende 7 4 7 anzichè 7 7
aaa
09/03/13 17:28
Perchè sbagli il metodo di scorrimento, tu devi rimanere a cancellare l' elemento successivo, finchè l' elmento successivo è spari
Ultima modifica effettuata da 09/03/13 17:36
09/03/13 18:38
dennis87
non è che potresti farmi vedere come si fa?
sono giorni che ci sto impazzendo ma non ne vengo mai a capo...
aaa