(* M2StackAddress.mod provides a generic stack for ADDRESS sized objects. Copyright (C) 2001-2024 Free Software Foundation, Inc. Contributed by Gaius Mulley . This file is part of GNU Modula-2. GNU Modula-2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Modula-2; see the file COPYING3. If not see . *) IMPLEMENTATION MODULE M2StackAddress ; FROM Storage IMPORT ALLOCATE, DEALLOCATE ; FROM M2Error IMPORT InternalError ; FROM M2Debug IMPORT Assert ; CONST MaxBucket = 10 ; TYPE StackBucket = POINTER TO RECORD bucket: ARRAY [0..MaxBucket-1] OF ADDRESS ; items : CARDINAL ; prev : StackBucket ; END ; StackOfAddress = POINTER TO RECORD tail: StackBucket ; END ; (* InitStackAddress - creates and returns a new stack. *) PROCEDURE InitStackAddress () : StackOfAddress ; VAR s: StackOfAddress ; BEGIN NEW (s) ; WITH s^ DO tail := NIL END ; RETURN s END InitStackAddress ; (* KillBucket - destroys a StackBucket and returns, NIL. *) PROCEDURE KillBucket (b: StackBucket) : StackBucket ; BEGIN IF b # NIL THEN b := KillBucket (b^.prev) ; DISPOSE (b) END ; RETURN NIL END KillBucket ; (* KillStackAddress - destroys a stack, returning NIL. *) PROCEDURE KillStackAddress (s: StackOfAddress) : StackOfAddress ; BEGIN IF s#NIL THEN s^.tail := KillBucket (s^.tail) ; DISPOSE (s) END ; RETURN NIL END KillStackAddress ; (* InitBucket - returns an empty StackBucket. *) PROCEDURE InitBucket (l: StackBucket) : StackBucket ; VAR b: StackBucket ; BEGIN NEW(b) ; WITH b^ DO items := 0 ; prev := l END ; RETURN( b ) END InitBucket ; (* PushAddress - pushes a word, w, onto, s. *) PROCEDURE PushAddress (s: StackOfAddress; w: ADDRESS) ; BEGIN IF s=NIL THEN InternalError ('stack has not been initialized') ELSE WITH s^ DO IF (tail=NIL) OR (tail^.items=MaxBucket) THEN tail := InitBucket(tail) END ; WITH tail^ DO IF items=1 DO IF b=NIL THEN InternalError ('stack underflow') ELSIF b^.items>=n THEN RETURN( b^.bucket[b^.items-n] ) ELSE Assert(b^.items=n THEN DEC( s^.tail^.items, n) ; RETURN (* all done exit *) ELSE b := s^.tail ; DEC(n, b^.items) ; s^.tail := s^.tail^.prev ; DISPOSE(b) END END END END ReduceAddress ; (* NoOfItemsInStackAddress - returns the number of items held in the stack, s. *) PROCEDURE NoOfItemsInStackAddress (s: StackOfAddress) : CARDINAL ; VAR b: StackBucket ; n: CARDINAL ; BEGIN IF IsEmptyAddress(s) THEN RETURN( 0 ) ELSE n := 0 ; b := s^.tail ; WHILE b#NIL DO INC (n, b^.items) ; b := b^.prev END ; RETURN( n ) END END NoOfItemsInStackAddress ; END M2StackAddress.