Stack of stacks possible? - stack

A doubt crossed my mind while studying stack, can we have a stack of many stacks, just like array matrices are array of many arrays? If yes, how can I possibly implement it?

Yes, you can totally have stacks of stacks. In Python for example, list can be used as a stack. So a list of list is essentially stack of stacks.
In C++, you can also declare a std::stack<std::stack<int> > to be a stack of int stacks.

Related

Copy-on-write for stacks

How to implement copy-on-write technique for stack management in postfix calculations of big numbers?
I want to optimize my system regarding operations like:
duplicate top of stack
swap the two top elements
copy the second element on stack to the top
rotate the stack making the third element on top
apply n-ary operations on the stack
A typical operation take a number of parameters from top of stack and leave a number of results instead.
My stack is implemented as an array where data grows from low-mem to hi-mem and pointers from hi-mem to low-mem.
As I can see, the problem is not in the copy-on-write technique per se, but in memory management and garbage collecting.
In Forth we cannot have operator overloading and should have an explicitly separate set of operations for each class of numbers. Then we have two options:
A set of operations over bigint objects (their handlers), with manual memory management, similar to operations over files, dynamic memory buffers, or other objects.
A full set of operations including the separate stack, like operations over floating-point numbers, with automatic memory management.
Note that option (2) contains (1) under the hood.
Reference counting
One approach to implement automatic memory management in option (2) is to use a dedicated stack (or maybe two stacks) and reference counting. The stack contains references to objects (buffers). The operations that alter data (like b::1+) should make copy of the buffer and replace the reference by a new one if the counter is greater than 1 (otherwise data can be altered in the place).
Placing an item (a reference) to the stack should increase its counter, removing from the stack should decrease its counter. When the counter become 0, the buffer should be freed.
Such operations like b::dup, b::over increase the counter. b::swap doesn't change any counter. b::drop decreases the counter (and frees the buffer if the counter is 0).
Moving an item from the stack into a bigint variable should not change the counter in the result. But the counter for the previous value of the variable (if any) should be decreased.
If named variables and constants are not enough (e.g., to have user-defined arrays), you may need to introduce into the API the pointers (a kind of anonymous variables) or handlers to bigint objects.
Immutable objects
Another approach to implement option (2) is to have immutable objects and garbage collection loop. In this approach we don't need to count references, but need to maintain the list of external pointers (including variables).
A simple example of such garbage collection can be found in the implementation of s-expressions by Peter Sovietov: Функциональное программирование на языке Форт ("Functional programming in Forth language" in Russian, but it can be easy translated using Google Translate).

Do stacks have indexes?

Yeah, so one of my friends said we can use indexes to traverse a stack, but I think he's wrong. Basically, I have a homework in which I had to write an algorithm using an array. I had to use two for loops to do it, so I was wondering how to do something like this with a stack:
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
x = A[i]+A[j]
}
}
There is no way right? And I have to use pop() and push() only to do whatever I need to do, right? Because I used an array and stack concurrently, but one of my friends told me I can't do that. I know we can implement a stack using an array, but the stack ADT doesn't have indexes (although they just said stack and not stack ADT).
said we can use indexes to traverse a stack, but I think he's wrong.
You're right, he's wrong.
There is no way [to do two nested loops] right?
You can access element at index if you have enough space for a temporary stack: pop to the index while storing the popped values onto a temp stack, remember the value, and then push the values back:
int GetAt(Stack s, int index) {
Stack temp;
while (temp.size() != index) {
temp.push(s.pop());
}
int res = temp.top();
while (!temp.empty()) {
s.push(temp.pop());
}
return res;
}
Yes, that's very, very slow.
Yes, a pure stack abstraction would not have indices. But pure abstractions rarely exist outside of Comp Sci classrooms and Haskell User's Groups, and most stack implementations can admit to something like this, because indeed, they are usually implemented using an array. At the end of the day, you don't get a prize for how "pure" something is, but rather for getting the job done. I can certainly imagine a situation in which you build up a stack, and then at some point, you need to process all the elements as given in your loop. Welcome to the real world!
"Stack" is an abstract concept, not something that exists in reality. In the real world, they are generally implemented as data in consecutive memory addresses, and so indexing them is certainly possible, depending on the language/library/API you're using. Without a specific language or library, there's really no way to answer a question like yours.
If what you really mean is, is there a way to do the calculation you mention with two data collections that can only be accessed by push/pop, then probably not without an intermediate array. But why would you want to? A stack is, by its very nature, intended to be used for algorithms that only need to access its data in a LIFO way. Why else would you use one?
Actually you're all wrong(tm)! With two stacks ("pure" stacks) you can implement an array, inefficiently. Suppose stack S1 has 10 items pushed on it, and you want item 5; just pop 4 items off of S1, pushing each on to S2 in turn. Then pop off one more and that is your item. Just keep track of the index of the item that is currently in use (on neither stack), and you can always retrieve any of the other items when you need them.
But this idea is absurd.
Look at Reverse Polish Notation for how to use stacks for computing.
http://en.wikipedia.org/wiki/Reverse_Polish_notation
Basically push the values, then pop them off and apply a function.
Stack have index. Depending on how you implement stack we can use array or link list to implement stack in array the indexing is start from left to right from zero. But we can do indexing in both ways either from
stack top element to bottom most element
bottom most element to top most element

How to find the current stack?

in Pharo, how can I find the currently evaluating stack?
Well, in fact, the issue aint that simple: thisContext can be a quite expensive operation, compared to like a message send.
In Visualworks Smalltalk, stack access is extermly expensive because it uses the native C-stack and thus any access to thisContext must reify the entire C-Stack into causally connected Smalltalk objects. That is, for each C stack frame a Smalltalk object is to be created (including possible JIT deoptimization) and furthermore all changes to these objects must be reflected back to the C stack.
In Pharo (and Squeak, for that matter) it is less awkward, since it uses Smalltalk objects for the stack. But still the object pool which caches stack frames is flushed upon each call. (Yes, other than eg in Java, pooling objects does improve performance in Squeak ... welcome back to the 90ies :)
You evaluate
thisContext contextStack
Here, thisContext is really a special variable that points to the currently active stack frame. Then, contextStack returns an array with the entire stack.

How does a stackless language work?

I've heard of stackless languages. However I don't have any idea how such a language would be implemented. Can someone explain?
The modern operating systems we have (Windows, Linux) operate with what I call the "big stack model". And that model is wrong, sometimes, and motivates the need for "stackless" languages.
The "big stack model" assumes that a compiled program will allocate "stack frames" for function calls in a contiguous region of memory, using machine instructions to adjust registers containing the stack pointer (and optional stack frame pointer) very rapidly. This leads to fast function call/return, at the price of having a large, contiguous region for the stack. Because 99.99% of all programs run under these modern OSes work well with the big stack model, the compilers, loaders, and even the OS "know" about this stack area.
One common problem all such applications have is, "how big should my stack be?". With memory being dirt cheap, mostly what happens is that a large chunk is set aside for the stack (MS defaults to 1Mb), and typical application call structure never gets anywhere near to using it up. But if an application does use it all up, it dies with an illegal memory reference ("I'm sorry Dave, I can't do that"), by virtue of reaching off the end of its stack.
Most so-called called "stackless" languages aren't really stackless. They just don't use the contiguous stack provided by these systems. What they do instead is allocate a stack frame from the heap on each function call. The cost per function call goes up somewhat; if functions are typically complex, or the language is interpretive, this additional cost is insignificant. (One can also determine call DAGs in the program call graph and allocate a heap segment to cover the entire DAG; this way you get both heap allocation and the speed of classic big-stack function calls for all calls inside the call DAG).
There are several reasons for using heap allocation for stack frames:
If the program does deep recursion dependent on the specific problem it is solving,
it is very hard to preallocate a "big stack" area in advance because the needed size isn't known. One can awkwardly arrange function calls to check to see if there's enough stack left, and if not, reallocate a bigger chunk, copy the old stack and readjust all the pointers into the stack; that's so awkward that I don't know of any implementations.
Allocating stack frames means the application never has to say its sorry until there's
literally no allocatable memory left.
The program forks subtasks. Each subtask requires its own stack, and therefore can't use the one "big stack" provided. So, one needs to allocate stacks for each subtask. If you have thousands of possible subtasks, you might now need thousands of "big stacks", and the memory demand suddenly gets ridiculous. Allocating stack frames solves this problem. Often the subtask "stacks" refer back to the parent tasks to implement lexical scoping; as subtasks fork, a tree of "substacks" is created called a "cactus stack".
Your language has continuations. These require that the data in lexical scope visible to the current function somehow be preserved for later reuse. This can be implemented by copying parent stack frames, climbing up the cactus stack, and proceeding.
The PARLANSE programming language I implemented does 1) and 2). I'm working on 3). It is amusing to note that PARLANSE allocates stack frames from a very fast-access heap-per-thread; it costs typically 4 machine instructions. The current implementation is x86 based, and the allocated frame is placed in the x86 EBP/ESP register much like other conventional x86 based language implementations. So it does use the hardware "contiguous stack" (including pushing and poppping) just in chunks. It also generates "frame local" subroutine calls the don't switch stacks for lots of generated utility code where the stack demand is known in advance.
Stackless Python still has a Python stack (though it may have tail call optimization and other call frame merging tricks), but it is completely divorced from the C stack of the interpreter.
Haskell (as commonly implemented) does not have a call stack; evaluation is based on graph reduction.
There is a nice article about the language framework Parrot. Parrot does not use the stack for calling and this article explains the technique a bit.
In the stackless environments I'm more or less familiar with (Turing machine, assembly, and Brainfuck), it's common to implement your own stack. There is nothing fundamental about having a stack built into the language.
In the most practical of these, assembly, you just choose a region of memory available to you, set the stack register to point to the bottom, then increment or decrement to implement your pushes and pops.
EDIT: I know some architectures have dedicated stacks, but they aren't necessary.
Call me ancient, but I can remember when the FORTRAN standards and COBOL did not support recursive calls, and therefore didn't require a stack. Indeed, I recall the implementations for CDC 6000 series machines where there wasn't a stack, and FORTRAN would do strange things if you tried to call a subroutine recursively.
For the record, instead of a call-stack, the CDC 6000 series instruction set used the RJ instruction to call a subroutine. This saved the current PC value at the call target location and then branches to the location following it. At the end, a subroutine would perform an indirect jump to the call target location. That reloaded saved PC, effectively returning to the caller.
Obviously, that does not work with recursive calls. (And my recollection is that the CDC FORTRAN IV compiler would generate broken code if you did attempt recursion ...)
There is an easy to understand description of continuations on this article: http://www.defmacro.org/ramblings/fp.html
Continuations are something you can pass into a function in a stack-based language, but which can also be used by a language's own semantics to make it "stackless". Of course the stack is still there, but as Ira Baxter described, it's not one big contiguous segment.
Say you wanted to implement stackless C. The first thing to realize is that this doesn't need a stack:
a == b
But, does this?
isequal(a, b) { return a == b; }
No. Because a smart compiler will inline calls to isequal, turning them into a == b. So, why not just inline everything? Sure, you will generate more code but if getting rid of the stack is worth it to you then this is easy with a small tradeoff.
What about recursion? No problem. A tail-recursive function like:
bang(x) { return x == 1 ? 1 : x * bang(x-1); }
Can still be inlined, because really it's just a for loop in disguise:
bang(x) {
for(int i = x; i >=1; i--) x *= x-1;
return x;
}
In theory a really smart compiler could figure that out for you. But a less-smart one could still flatten it as a goto:
ax = x;
NOTDONE:
if(ax > 1) {
x = x*(--ax);
goto NOTDONE;
}
There is one case where you have to make a small trade off. This can't be inlined:
fib(n) { return n <= 2 ? n : fib(n-1) + fib(n-2); }
Stackless C simply cannot do this. Are you giving up a lot? Not really. This is something normal C can't do well very either. If you don't believe me just call fib(1000) and see what happens to your precious computer.
Please feel free to correct me if I'm wrong, but I would think that allocating memory on the heap for each function call frame would cause extreme memory thrashing. The operating system does after all have to manage this memory. I would think that the way to avoid this memory thrashing would be a cache for call frames. So if you need a cache anyway, we might as well make it contigous in memory and call it a stack.

Can i configure a ARM processor for Ascending Stack growth direction?

There has been one question here which talked about stack growth direction. To which Michael Burr had replied saying in ARM processors stack growth direction can be configured - i.e. either descending (normal behaviour) stack grows towards zero address (lower address) in memory or ascending, i.e. stack grows towards higher address in memory.
What is the direction of stack growth in most modern systems?
My question is: in ARM processors, how can I make the stack grow in ascending direction?
How do I configure the stack as ascending as by default it is descending? Any register bit set/reset, etc.
Well, the ARM processors don't maintain a stack directly-- but they do have instructions that are designed with that in mind: LDM and STM. So if you use STMDB at the start of a function and LDMIA at the end, you effectively have a full+descending stack: the assemblers I remember using allowed you to write "STMFD" and "LDMFD" as aliases. (A "full" stack is one where the stack pointer points to the latest word on the stack, as opposed to the next location to use)
So it's not something you can simply reconfigure at runtime: although if you were writing your own operating system with its own call convention, you could choose to use an ascending stack. Similarly, you could also choose not to use R13 as the stack pointer- that's just part of the calling convention too. This choice effectively gets embedded into the implementation of every function that uses the stack.
You have the __user_initial_stackheap() function which helps you change the SP using Stack-Start,Stack-End & heap relocation using Heap-Start,Heap-End. This function can be used during the time of the initialization since the ARM would use this to redirect Stack and Heap.
Also, you have option to use a Single-region or two-memory model[depending on your requirement]. I have used this API when I was writing UseCases which were using ARM926EJ-S.
This document was of help during my development and might be helpful to you as well.
Hope this helps.
-hjsblogger
Hmmm thumb/thumb2 might limit you to push/pop, and with thumb2 only ARMs out there I dont know that we can generically say you can go both ways. Traditional arm instructions, yes you can ldmia or ldmdb (increment after or decrement before) and stmdb and stmia. How do you make a C compiler for example climb up in addresses instead of down autmatically? Dont know.
It is like big endian on ARM, just because you can you probably dont want to because of the headaches it brings along with it.

Resources