I have a strange question concerning subroutines: As I'm creating a minimal language and I don't want to add high-level loops like while or for I was planning on just adding gotos to keep it Turing-Complete.
Now I thought, eww - gotos - I wouldn't want to program in that language if I had to use gotos so often. So I thought about adding subroutines instead.
I see the difference as the following:
gotos
Go to (captain obvious) a previously defined point and continue executing the program from there. Leads to hardly understandable and buggy code, I think that's a fact.
subroutines
Similiar: You define their starting point somewhere, as you call them the program jumps there - but the subroutine can go back to the point it was called from with return.
Okay. Why didn't I just add the more function-like, nice looking subroutines? Because:
In order to make return work if I call subroutines from within subroutines from within other subroutines, I'd have to use a stack containing the point where the currently running subroutine came from at top.
That would then mean that I would, if I create loops using the subroutines, end up with an extremely memory-eating, overflowing stack with return locations. Not good.
Don't think of my subroutines as functions. They are just gotos that return to the point they were called from, they don't actually give back values like the return x; statement in nearly all today's languages.
Now to my actual questions:
How can I solve the above problem with the stack overflow on loops with subroutines? Do I have to add a separate goto language construct without the return option?
Assembler doesn't have loops but as I have seen myJumpPoint:, jnz, jz, retn. That means to me that there must also be a stack containing all the return locations.
Am I right with that?
What about long running loops then? Don't they overflow the stack/eat memory then?
Am I getting the retn symbol in assembler totally wrong? If yes, please explain it to me.