Seite 1 von 2

Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 14.12.2011 18:53
von alen
Hallo Community,

ich bin mal wieder in Sachen PB unterwegs und stosse auf ein Grundsatzproblem.

Es wird eine Procedure abgearbeitet die sich selbst wieder aufruft. Nach dem Beispiel als wenn man durch Verzeichnissse oder in der Registry den kompletten Pfad durchsucht. So weit, so gut. Klappt auch.

Was ich brauche ist aus dieser Rekursiven Procedure beim Vorkommen einer Bedingung frühzeitig ausszuteigen mit einem Rückggabewert bsp. der String der dort gefunden wurde. Sprich sobald die Bedingung eintrifft, mit dem Rückgabewert im Gepäck aus der Procedure raus.

Welches ist die beste Praxis für sowas ? Komme auf keine praktikable Lösung.

Grüße
Alen

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 14.12.2011 19:33
von RSBasic
Suchst du vielleicht ProcedureReturn?
Oder bei Schleifen Break?

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 14.12.2011 20:32
von NicTheQuick
Ich würde das so in der Art machen:

Code: Alles auswählen

Procedure recursiveFunction(parameter1, parameter2, *cancelRecursion.Integer = 0)
	Protected cancel.i = #False
	If (*cancelRecursion = 0)
		*cancelRecursion = @cancel
	EndIf

	;mach was
	
	result = recursiveFunction(wert1, wert2, *cancelRecursion)
	If (*cancelRecursion\i)
		;brich die Rekursion ab
		ProcedureReturn
	EndIf
	
	;mach was
	
	result = recursiveFunction(wert1, wert2, *cancelRecursion)
	If (*cancelRecursion\i)
		;brich die Rekursion ab
		ProcedureReturn
	EndIf
	
	;mach was
	
	;usw.
	
	If irgendwas_schlimmes_ist_passiert
		*cancelRecursion\i = #True
		ProcedureReturn
	EndIf
	
	;alles ok, gib Ergebnis aus
	ProcedureReturn ergebnis
EndProcedure

Debug recursiveFunction(123, 456)
Ich hoffe der Code ist selbsterklärend.

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 14.12.2011 21:21
von Danilo
RSBasic hat geschrieben:Suchst du vielleicht ProcedureReturn?
Oder bei Schleifen Break?
Das heißt aber das bei einer Rekursionstiefe von beispielsweise 10.000 dann
auch 10.000 male zurückgesprungen wird.
Ich vermute mal das alen mit aussteigen meinte, die ganze Rekursion komplett
und unverzüglich zu verlassen und nicht tausende male zurück zu springen.

Für PB ist mir dafür aber auch kein sauberer Weg bekannt. Mit Goto rausspringen
räumt den Stack nicht auf. Exceptions gibt es nicht.

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 14.12.2011 21:46
von ts-soft
:?:

Code: Alles auswählen

EnableExplicit

Global newvalue

Procedure Zaehle(value)
  value + 1
  If value < 1000
    Zaehle(value)
  Else
    newvalue = value
    ProcedureReturn
  EndIf
EndProcedure

Zaehle(1)
Debug newvalue

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 14.12.2011 22:52
von NicTheQuick
Weiterhin sei noch gesagt, dass man jede Rekursion auch in eine Iteration verwandeln kann. Dazu baut man sich einfach seinen eigenen Stack, falls man ihn überhaupt braucht. Das kommt eben immer auf das zu Grunde liegend Problem an. Aber funktionieren tut es alle mal und man bekommt außerdem keinen Stack-Overflow, der bei tiefen Rekursionen mal schnell erreicht sein kann. Interessanterweise stürzt bei PB einfach das Programm samt Debugger ab, wenn man einen Stack-Overflow provoziert. Ich denke das sollte der Debugger eigentlich auch abfangen.

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 15.12.2011 15:06
von CSHW89
Etwas unsauber, aber mit Speicherung des Stacks, und Goto gehts so:

Code: Alles auswählen

Global __SaveStack

Macro SaveStack()
  CompilerIf #PB_Compiler_Processor =#PB_Processor_x86
    !MOV dword[v___SaveStack],ESP
  CompilerElse
    CompilerIf #PB_Compiler_Processor =#PB_Processor_x64
      !MOV qword[v___SaveStack],RSP
    CompilerElse
      CompilerError "Processor not supported by try/catch handler"
    CompilerEndIf
  CompilerEndIf
EndMacro

Macro GotoBack()
  CompilerIf #PB_Compiler_Processor =#PB_Processor_x86
    !MOV ESP,dword[v___SaveStack]
  CompilerElse
    CompilerIf #PB_Compiler_Processor =#PB_Processor_x64
      !MOV RSP,qword[v___SaveStack]
    CompilerElse
      CompilerError "Processor not supported by try/catch handler"
    CompilerEndIf
  CompilerEndIf
  Goto back
EndMacro


Procedure Rec(n)
  Debug "Start "+Str(n)
  If (n = 0)
    GotoBack()
  EndIf
  Rec(n-1)
  Debug "Hier kommste niemals hin"
EndProcedure


Procedure test()
  Protected str.s
  
  str = "Fertig!"
  
  SaveStack()
  Rec(5)
  back:
  Debug str
EndProcedure

test()
Mit einem etwas modifiziertem Code aus dem CodeArchiv benutze ich das immer für Try/Catch-Blöcke, und funktioniert wunderbar.

lg Kevin

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 15.12.2011 15:09
von ts-soft
Abgesehen davon, das dieser Code bei mir einen ASM error wirft, warum wollt Ihr immer den Stack
bereinigen, das macht PB doch bei einem ProcedureReturn automatisch, sollte also vollkommen
unnötig sein?

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 15.12.2011 15:14
von NicTheQuick
Nein, PB macht das nicht, wenn man einfach so mit einem Goto aus einer Procedure heraus springt.

Re: Prinzipfrage: Ausstieg aus einer Rekusiven Procedure

Verfasst: 15.12.2011 15:20
von ts-soft
NicTheQuick hat geschrieben:Nein, PB macht das nicht, wenn man einfach so mit einem Goto aus einer Procedure heraus springt.
Naja, aber warum sollte man mit einem Goto aus der Procedure springen, das ist es ja was ich nicht verstehe,
ist doch vollkommen unnötig oder übersehe ich hier etwas?

IMHO kann man rekursive Funktionen problemlos mit einem ProcedureReturn verlassen, so habe ich das gelesen.