Δευτέρα, 1 Ιανουαρίου 2018

Mastering Stacks in M2000

In M2000, every command executed with a current stack along (maybe used or not). This stack is only for values, and for any kind of them. When we call a module arguments passed to current stack. When a module ends then stack maybe have more items, or not, but called module has the control for it. When we use a user function we get a new stack, and at return stack object dropped. The same hold for threads and event Functions, they have own stack, Thread has same stack for all calling intervals, and event function called always with a new stack, and for that call only.
We can use stack objects, and stack, for any purpose, as FIFO or LIFO queue. A stack item maybe is a stack object too. In this example we pass a pointer of a stack object to itself, as an item - see last statements.
There is no null in M2000, so if we make a pointer to object we can pass another pointer. To erase items of a stack object we can execute Flush command in a block Stack object_pointer { Flush }, or for current stack just use Flush. We can't handle current stack pointer, but we can handle pointers in variables of type stack object (named mStiva and is an internal COM object). So we can pass an empty stack just making a new stack object and passing pointer to it.
When a variable which point to a stack object get out of scope decrement objects reference counter, and maybe can erased or not depends of counter value.
We don't have New command in M2000 to make new objects. For stack object we use Stack or Stack:=list of items (Stack:=1,2,3 place three items in a new stack object). Although there is a block which change temporary the current stack with a new one using Stack New {} and after end of statements in block we get old stack back (temporary old stack can't be used, it's sealed from program)

First program show the iterator object for stack:

Flush ' Empty Stack
\\ make b as a stack of two stacks
b=Stack:=(Stack:=1,2, 100),(Stack:=3,4,5,6)
Module k (a, b) { ' (a, b) is a statement:  Read a, b
      Print a,b,
      n=[] ' get Stack and place an empty one
      Print n
}
Push 1000 ' push 1000 to Stack as top item
Stack New {
      b1=each(b)
      While b1 {
            k !stackitem(b1)
      }
}
Read M ' now we read top item
Print M ' 1000
Print Len(b)
b1=each(b)
While b1 {
      Print Len(stackitem(b1)) ' 0 all items are cleared from previous pop all using !
}
\\ make a new one
b=Stack:=(Stack:=1,2, 100),(Stack:=3,4,5,6)
Stack New {
      b1=each(b)
      While b1 {
            k !Stack(stackitem(b1)) ' now we use a copy of stack
            Print Len(stackitem(b1)) ' so each stack in stack has items inside
            Return b, b1^+1:=Stack ' b1^ is the cursor of iterator b1, we change base to 1
            Print Len(stackitem(b1)) ' 0 length is empty now
      }
}

Here is the big one.



\\ Stack Demo - (include pointers to stack object too)
Form 100, 80
Push 1, 2
Stack ' just display stack items
Stack New {
      Push 3, 4
      Stack
      Stack New {
            Push 5, 6
            Stack
      }
      Stack
      Print Stack.Size 'print 2
      Print Empty ' print 0 means false
      Print IsNum ' print -1 means true, is number
      Print IsLet ' print 0 it isn't letters (string)
      Print Envelope$() ' print NN two numbers
}
Stack ' 2 1
Over 2 ' copy 2nd as top item
Stack ' 1 2 1
Shift 3 ' shift 3rd as top item
Stack ' 1 1 2
Data 3, 4, 5 ' place numbers to end of stack
Stack  ' 1 1 2 3 4 5
ShiftBack 2, 3 ' shift back 3 items to second position from top
Stack ' 3 1 1 2 4 5
Push 8, 7
Stack ' 7 8 3 1 1 2 4 5
ShiftBack Stack.Size-1,2 ' shift back 2 items to position last minus one
Stack ' 3 1 1 2 4 5 7 8
ShiftBack 4
Stack ' 1 1 2 3 4 5 7 8
Drop
Stack ' 1 2 3 4 5 7 8
Over Stack.Size, Stack.Size ' duplicate stack items, as two rows in a row
Stack ' 1 2 3 4 5 7 8 1 2 3 4 5 7 8
Shift 14
Drop
Push 8.5
ShiftBack 14
Drop
Push 1.5
Stack ' 1.5 2 3 4 5 7 8 1 2 3 4 5 7 8.5
ShiftBack 8,-8 ' get 7 items from top and place it in reverse order
Stack ' 1 2 3 4 5 7 8.5 8 7 5 4 3 2 1.5
Push 6,6
ShiftBack 7: ShiftBack 11
Stack ' 1 2 3 4 5 6 7 8.5 8 7 6 5 4 3 2 1.5
Shift 9,-9 ' get 8 items from top and place it in reverse order, from 9th position
Stack ' 1.5 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8.5
A=[] ' get all items in private stack
Print Empty ' is empty
Print Len(A) ' has 16 items
B=Stack(A) ' B get a copy of A items
Print A ' 1.5 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8.5 in columns
Print B ' 1.5 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8.5 in columns
Push "a string" ' push one item to current stack
Stack A ' drop A to current stack
Stack ' "a string" 1.5 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8.5
Print Len(A), Stack.Size, Len(B) ' 0 17 16
A=B ' A point to B
Stack B {
      Print Stack.Size ' 16
      Drop 8 ' drop top 8 items
}
Print B ' 1 2 3 4 5 6 7 8.5 in columns
Print A ' 1 2 3 4 5 6 7 8.5 in columns
A=[] ' now A has a new pointer, and get current stack object, and leave in current stack object a new empty stack
Print Len(A), Stack.Size, Len(B) ' 17 0 8
M=Each(B,4,1)
While M {
      Push StackItem(M)
}
Stack B {Drop 4}
Print Len(A), Stack.Size, Len(B) ' 17 4 4
Print B ' 5 6 7 8.5 in columns
Stack ' 1 2 3 4
A=Stack(A, []) ' merge current stack items to A, leave current stack item an empty stack
Print Len(A), Stack.Size, Len(B) ' 21 0 4
A=Stack(A, B) ' merge a copy of B
Print Len(A), Stack.Size, Len(B) ' 25 0 4
Stack A { ' attach A as current stack, and old stack reserved to attach it at the exit of block
      Stack B ' dump B to A - merging at bottom
}
Print Len(A), Stack.Size, Len(B) ' 29 0 0
' we can create a stack object with values
B=Stack:="A", "B","C"
Stack A {
      Push !B ' merge top B, empty B
}
Print A
Print Len(A), Stack.Size, Len(B) ' 32 0 0
B=Stack(A, Stack:=0,-1,-2) ' get a copy of A and merge a copy of a new stack with 3 items
Print Len(A), Stack.Size, Len(B) ' 32 0 35
B=Stack((Stack:=0,-1,-2), A) ' get a copy of a new stack with 3 items and merge a copy of A
Print Len(A), Stack.Size, Len(B) ' 32 0 35
Return A, 1:=StackItem$(A)+" ok", 5:=StackItem(A,5)+1, 6:=StackItem(A,6)+1
Print A
Stack A {
      Flush 'empty stack
}
Stack B ' empty B but first dump to  current stack
Print Len(A), Stack.Size, Len(B) ' 0 35 0
Flush 'empty stack
Print Len(A), Stack.Size, Len(B) ' 0 0 0
\\ we can't take a pointer to current stack. A=[] get all items of current stack and leave a new empty current stack.
Dim A(10)
A(3)=Stack:=1,2,3,4
N=A(3)
Print Len(N)
Stack N {Data 5,6,7}
Print Len(N), Len(A(3)) ' 8 8
Module CheckMe (M) {
      Stack M {Drop 4}
}
CheckMe N
Print Len(N), Len(A(3)) ' 3 3
' define again CheckMe
Module CheckMe (&M) {
      M=Stack:=100,200,"ok"
}
CheckMe &N
Print N ' now N has a new object
Print A(3)
A(3)=N ' now we put pointer N to A(3)
Print A(3)
Stack A(3) { Shift Len(A(3)) : Drop} ' drop last item
Print Len(N), Len(A(3)) ' 2 2
Print Type$(N), Type$(A(3)) ' mStiva mStiva
Print N ' 100 200
Print A(3) ' 100 200
Stack N { Data A(3)}
Return A(3), 1:=1000
Print N ' 1000 200 and leave a column blank (beacuse it is an object, a pointer to a mstiva)
Print Len(N), Len(A(3)) ' 3 3
N=Stack(A(3)) ' get a copy of A(3) ' shallow copy
Return A(3), 1:=2000
Print A(3) ' 2000 200 blank column
Print N ' 1000 200 blank column
Rem :
A(3)=Stack ' Empty A(3) changing pointer to a new empty stack
Rem : Stack A(3) {Flush} ' try this, just flush stack in A(3), without changing object
N1=StackItem(N,3) ' point to old A(3) object
Print Len(N1) ' if we use second rem then after here all will be empty
Print N1 ' 2000 200 blank column
Swap N1, A(3) ' swap pointers only
Print N1 ' nothing is empty. Just a blank row
Print A(3) ' 2000 200 blank column
Print N ' 1000 200 blank column
N=Stack ' empty N with a new stack object
\\ demo ends here